Whamcloud - gitweb
4cf7592b811fefa0f4afe9badb9d44a5e1899191
[fs/lustre-release.git] / lustre / kernel_patches / patches / linux-2.4.19-pre1-xattr-0.8.54.patch
1  Documentation/Configure.help  |   66 ++
2  arch/alpha/defconfig          |    7 
3  arch/alpha/kernel/entry.S     |   12 
4  arch/arm/defconfig            |    7 
5  arch/arm/kernel/calls.S       |   24 
6  arch/i386/defconfig           |    7 
7  arch/ia64/defconfig           |    7 
8  arch/ia64/kernel/entry.S      |   24 
9  arch/m68k/defconfig           |    7 
10  arch/mips/defconfig           |    7 
11  arch/mips64/defconfig         |    7 
12  arch/ppc/defconfig            |   14 
13  arch/ppc64/kernel/misc.S      |    2 
14  arch/s390/defconfig           |    7 
15  arch/s390/kernel/entry.S      |   24 
16  arch/s390x/defconfig          |    7 
17  arch/s390x/kernel/entry.S     |   24 
18  arch/s390x/kernel/wrapper32.S |   92 +++
19  arch/sparc/defconfig          |    7 
20  arch/sparc/kernel/systbls.S   |   10 
21  arch/sparc64/defconfig        |    7 
22  arch/sparc64/kernel/systbls.S |   20 
23  fs/Config.in                  |   14 
24  fs/Makefile                   |    3 
25  fs/ext2/Makefile              |    4 
26  fs/ext2/file.c                |    5 
27  fs/ext2/ialloc.c              |    2 
28  fs/ext2/inode.c               |   34 -
29  fs/ext2/namei.c               |   14 
30  fs/ext2/super.c               |   29 
31  fs/ext2/symlink.c             |   14 
32  fs/ext2/xattr.c               | 1212 +++++++++++++++++++++++++++++++++++++++++
33  fs/ext2/xattr_user.c          |  103 +++
34  fs/ext3/Makefile              |   10 
35  fs/ext3/file.c                |    5 
36  fs/ext3/ialloc.c              |    2 
37  fs/ext3/inode.c               |   35 -
38  fs/ext3/namei.c               |   21 
39  fs/ext3/super.c               |   36 +
40  fs/ext3/symlink.c             |   14 
41  fs/ext3/xattr.c               | 1225 ++++++++++++++++++++++++++++++++++++++++++
42  fs/ext3/xattr_user.c          |  111 +++
43  fs/jfs/jfs_xattr.h            |    6 
44  fs/jfs/xattr.c                |    6 
45  fs/mbcache.c                  |  648 ++++++++++++++++++++++
46  include/asm-arm/unistd.h      |    2 
47  include/asm-ia64/unistd.h     |   13 
48  include/asm-ppc64/unistd.h    |    2 
49  include/asm-s390/unistd.h     |   15 
50  include/asm-s390x/unistd.h    |   15 
51  include/asm-sparc/unistd.h    |   24 
52  include/asm-sparc64/unistd.h  |   24 
53  include/linux/cache_def.h     |   15 
54  include/linux/errno.h         |    4 
55  include/linux/ext2_fs.h       |   31 -
56  include/linux/ext2_xattr.h    |  157 +++++
57  include/linux/ext3_fs.h       |   31 -
58  include/linux/ext3_jbd.h      |    8 
59  include/linux/ext3_xattr.h    |  157 +++++
60  include/linux/fs.h            |    2 
61  include/linux/mbcache.h       |   69 ++
62  kernel/ksyms.c                |    4 
63  mm/vmscan.c                   |   35 +
64  fs/ext3/ext3-exports.c        |   14 +  
65  64 files changed, 4355 insertions(+), 195 deletions(-)
66
67 Index: linux-2.4.19-pre1/Documentation/Configure.help
68 ===================================================================
69 --- linux-2.4.19-pre1.orig/Documentation/Configure.help 2004-01-14 01:11:29.000000000 +0300
70 +++ linux-2.4.19-pre1/Documentation/Configure.help      2004-01-14 01:11:49.000000000 +0300
71 @@ -14035,6 +14035,39 @@
72    be compiled as a module, and so this could be dangerous.  Most
73    everyone wants to say Y here.
74  
75 +Ext2 extended attributes
76 +CONFIG_EXT2_FS_XATTR
77 +  Extended attributes are name:value pairs associated with inodes by
78 +  the kernel or by users (see the attr(5) manual page, or visit
79 +  <http://acl.bestbits.at/> for details).
80 +
81 +  If unsure, say N.
82 +
83 +Ext2 extended attribute block sharing
84 +CONFIG_EXT2_FS_XATTR_SHARING
85 +  This options enables code for sharing identical extended attribute
86 +  blocks among multiple inodes.
87 +
88 +  Usually, say Y.
89 +
90 +Ext2 extended user attributes
91 +CONFIG_EXT2_FS_XATTR_USER
92 +  This option enables extended user attributes on ext2. Processes can
93 +  associate extended user attributes with inodes to store additional
94 +  information such as the character encoding of files, etc. (see the
95 +  attr(5) manual page, or visit <http://acl.bestbits.at/> for details).
96 +
97 +  If unsure, say N.
98 +
99 +Ext2 trusted extended attributes
100 +CONFIG_EXT2_FS_XATTR_TRUSTED
101 +  This option enables extended attributes on ext2 that are accessible
102 +  (and visible) only to users capable of CAP_SYS_ADMIN. Usually this
103 +  is only the super user. Trusted extended attributes are meant for
104 +  implementing system/security services.
105 +
106 +  If unsure, say N.
107 +
108  Ext3 journalling file system support (EXPERIMENTAL)
109  CONFIG_EXT3_FS
110    This is the journalling version of the Second extended file system
111 @@ -14067,6 +14100,39 @@
112    of your root partition (the one containing the directory /) cannot
113    be compiled as a module, and so this may be dangerous.
114  
115 +Ext3 extended attributes
116 +CONFIG_EXT3_FS_XATTR
117 +  Extended attributes are name:value pairs associated with inodes by
118 +  the kernel or by users (see the attr(5) manual page, or visit
119 +  <http://acl.bestbits.at/> for details).
120 +
121 +  If unsure, say N.
122 +
123 +Ext3 extended attribute block sharing
124 +CONFIG_EXT3_FS_XATTR_SHARING
125 +  This options enables code for sharing identical extended attribute
126 +  blocks among multiple inodes.
127 +
128 +  Usually, say Y.
129 +
130 +Ext3 extended user attributes
131 +CONFIG_EXT3_FS_XATTR_USER
132 +  This option enables extended user attributes on ext3. Processes can
133 +  associate extended user attributes with inodes to store additional
134 +  information such as the character encoding of files, etc. (see the
135 +  attr(5) manual page, or visit <http://acl.bestbits.at/> for details).
136 +
137 +  If unsure, say N.
138 +
139 +Ext3 trusted extended attributes
140 +CONFIG_EXT3_FS_XATTR_TRUSTED
141 +  This option enables extended attributes on ext3 that are accessible
142 +  (and visible) only to users capable of CAP_SYS_ADMIN. Usually this
143 +  is only the super user. Trusted extended attributes are meant for
144 +  implementing system/security services.
145 +
146 +  If unsure, say N.
147 +
148  Journal Block Device support (JBD for ext3) (EXPERIMENTAL)
149  CONFIG_JBD
150    This is a generic journalling layer for block devices.  It is
151 Index: linux-2.4.19-pre1/arch/alpha/defconfig
152 ===================================================================
153 --- linux-2.4.19-pre1.orig/arch/alpha/defconfig 2001-11-20 02:19:42.000000000 +0300
154 +++ linux-2.4.19-pre1/arch/alpha/defconfig      2004-01-14 01:11:49.000000000 +0300
155 @@ -1,6 +1,13 @@
156  #
157  # Automatically generated make config: don't edit
158  #
159 +CONFIG_EXT3_FS_XATTR=y
160 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
161 +# CONFIG_EXT3_FS_XATTR_USER is not set
162 +# CONFIG_EXT2_FS_XATTR is not set
163 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
164 +# CONFIG_EXT2_FS_XATTR_USER is not set
165 +# CONFIG_FS_MBCACHE is not set
166  CONFIG_ALPHA=y
167  # CONFIG_UID16 is not set
168  # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
169 Index: linux-2.4.19-pre1/arch/alpha/kernel/entry.S
170 ===================================================================
171 --- linux-2.4.19-pre1.orig/arch/alpha/kernel/entry.S    2001-11-10 00:45:35.000000000 +0300
172 +++ linux-2.4.19-pre1/arch/alpha/kernel/entry.S 2004-01-14 01:11:49.000000000 +0300
173 @@ -1148,3 +1148,16 @@
174         .quad sys_gettid
175         .quad sys_readahead
176         .quad sys_ni_syscall                    /* 380, sys_security */
177 +       .quad sys_ni_syscall                    /* 381, sys_tkill */
178 +       .quad sys_setxattr
179 +       .quad sys_lsetxattr
180 +       .quad sys_fsetxattr
181 +       .quad sys_getxattr                      /* 385 */
182 +       .quad sys_lgetxattr
183 +       .quad sys_fgetxattr
184 +       .quad sys_listxattr
185 +       .quad sys_llistxattr
186 +       .quad sys_flistxattr                    /* 390 */
187 +       .quad sys_removexattr
188 +       .quad sys_lremovexattr
189 +       .quad sys_fremovexattr
190 Index: linux-2.4.19-pre1/arch/arm/defconfig
191 ===================================================================
192 --- linux-2.4.19-pre1.orig/arch/arm/defconfig   2001-05-20 04:43:05.000000000 +0400
193 +++ linux-2.4.19-pre1/arch/arm/defconfig        2004-01-14 01:11:49.000000000 +0300
194 @@ -1,6 +1,13 @@
195  #
196  # Automatically generated make config: don't edit
197  #
198 +CONFIG_EXT3_FS_XATTR=y
199 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
200 +# CONFIG_EXT3_FS_XATTR_USER is not set
201 +# CONFIG_EXT2_FS_XATTR is not set
202 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
203 +# CONFIG_EXT2_FS_XATTR_USER is not set
204 +# CONFIG_FS_MBCACHE is not set
205  CONFIG_ARM=y
206  # CONFIG_EISA is not set
207  # CONFIG_SBUS is not set
208 Index: linux-2.4.19-pre1/arch/arm/kernel/calls.S
209 ===================================================================
210 --- linux-2.4.19-pre1.orig/arch/arm/kernel/calls.S      2001-10-08 21:39:18.000000000 +0400
211 +++ linux-2.4.19-pre1/arch/arm/kernel/calls.S   2004-01-14 01:11:49.000000000 +0300
212 @@ -236,6 +236,22 @@
213                 .long   SYMBOL_NAME(sys_mincore)
214  /* 220 */      .long   SYMBOL_NAME(sys_madvise)
215                 .long   SYMBOL_NAME(sys_fcntl64)
216 +               .long   SYMBOL_NAME(sys_ni_syscall) /* TUX */
217 +               .long   SYMBOL_NAME(sys_ni_syscall) /* Security */
218 +               .long   SYMBOL_NAME(sys_gettid)
219 + /* 225 */     .long   SYMBOL_NAME(sys_readahead)
220 +               .long   SYMBOL_NAME(sys_setxattr)
221 +               .long   SYMBOL_NAME(sys_lsetxattr)
222 +               .long   SYMBOL_NAME(sys_fsetxattr)
223 +               .long   SYMBOL_NAME(sys_getxattr)
224 +/* 230 */      .long   SYMBOL_NAME(sys_lgetxattr)
225 +               .long   SYMBOL_NAME(sys_fgetxattr)
226 +               .long   SYMBOL_NAME(sys_listxattr)
227 +               .long   SYMBOL_NAME(sys_llistxattr)
228 +               .long   SYMBOL_NAME(sys_flistxattr)
229 +/* 235 */      .long   SYMBOL_NAME(sys_removexattr)
230 +               .long   SYMBOL_NAME(sys_lremovexattr)
231 +               .long   SYMBOL_NAME(sys_fremovexattr)
232  __syscall_end:
233  
234                 .rept   NR_syscalls - (__syscall_end - __syscall_start) / 4
235 Index: linux-2.4.19-pre1/arch/i386/defconfig
236 ===================================================================
237 --- linux-2.4.19-pre1.orig/arch/i386/defconfig  2004-01-14 01:10:36.000000000 +0300
238 +++ linux-2.4.19-pre1/arch/i386/defconfig       2004-01-14 01:11:49.000000000 +0300
239 @@ -1,6 +1,13 @@
240  #
241  # Automatically generated make config: don't edit
242  #
243 +CONFIG_EXT3_FS_XATTR=y
244 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
245 +# CONFIG_EXT3_FS_XATTR_USER is not set
246 +# CONFIG_EXT2_FS_XATTR is not set
247 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
248 +# CONFIG_EXT2_FS_XATTR_USER is not set
249 +# CONFIG_FS_MBCACHE is not set
250  CONFIG_X86=y
251  CONFIG_ISA=y
252  # CONFIG_SBUS is not set
253 Index: linux-2.4.19-pre1/arch/i386/kernel/entry.S
254 ===================================================================
255 --- linux-2.4.19-pre1.orig/arch/i386/kernel/entry.S     2004-01-14 01:11:46.000000000 +0300
256 +++ linux-2.4.19-pre1/arch/i386/kernel/entry.S  2004-01-14 01:11:49.000000000 +0300
257 @@ -619,18 +619,18 @@
258         .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
259         .long SYMBOL_NAME(sys_gettid)
260         .long SYMBOL_NAME(sys_readahead)        /* 225 */
261 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for setxattr */
262 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for lsetxattr */
263 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for fsetxattr */
264 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for getxattr */
265 -       .long SYMBOL_NAME(sys_ni_syscall)       /* 230 reserved for lgetxattr */
266 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for fgetxattr */
267 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for listxattr */
268 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for llistxattr */
269 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for flistxattr */
270 -       .long SYMBOL_NAME(sys_ni_syscall)       /* 235 reserved for removexattr */
271 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for lremovexattr */
272 -       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for fremovexattr */
273 +       .long SYMBOL_NAME(sys_setxattr)
274 +       .long SYMBOL_NAME(sys_lsetxattr)
275 +       .long SYMBOL_NAME(sys_fsetxattr)
276 +       .long SYMBOL_NAME(sys_getxattr)
277 +       .long SYMBOL_NAME(sys_lgetxattr)        /* 230 */
278 +       .long SYMBOL_NAME(sys_fgetxattr)
279 +       .long SYMBOL_NAME(sys_listxattr)
280 +       .long SYMBOL_NAME(sys_llistxattr)
281 +       .long SYMBOL_NAME(sys_flistxattr)
282 +       .long SYMBOL_NAME(sys_removexattr)      /* 235 */
283 +       .long SYMBOL_NAME(sys_lremovexattr)
284 +       .long SYMBOL_NAME(sys_fremovexattr)
285  
286         .rept NR_syscalls-(.-sys_call_table)/4
287                 .long SYMBOL_NAME(sys_ni_syscall)
288 Index: linux-2.4.19-pre1/arch/ia64/defconfig
289 ===================================================================
290 --- linux-2.4.19-pre1.orig/arch/ia64/defconfig  2001-11-10 01:26:17.000000000 +0300
291 +++ linux-2.4.19-pre1/arch/ia64/defconfig       2004-01-14 01:11:49.000000000 +0300
292 @@ -1,6 +1,13 @@
293  #
294  # Automatically generated make config: don't edit
295  #
296 +CONFIG_EXT3_FS_XATTR=y
297 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
298 +# CONFIG_EXT3_FS_XATTR_USER is not set
299 +# CONFIG_EXT2_FS_XATTR is not set
300 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
301 +# CONFIG_EXT2_FS_XATTR_USER is not set
302 +# CONFIG_FS_MBCACHE is not set
303  
304  #
305  # Code maturity level options
306 Index: linux-2.4.19-pre1/arch/ia64/kernel/entry.S
307 ===================================================================
308 --- linux-2.4.19-pre1.orig/arch/ia64/kernel/entry.S     2001-11-10 01:26:17.000000000 +0300
309 +++ linux-2.4.19-pre1/arch/ia64/kernel/entry.S  2004-01-14 01:11:49.000000000 +0300
310 @@ -1130,18 +1130,18 @@
311         data8 sys_getdents64
312         data8 sys_getunwind                     // 1215
313         data8 sys_readahead
314 -       data8 ia64_ni_syscall
315 -       data8 ia64_ni_syscall
316 -       data8 ia64_ni_syscall
317 -       data8 ia64_ni_syscall                   // 1220
318 -       data8 ia64_ni_syscall
319 -       data8 ia64_ni_syscall
320 -       data8 ia64_ni_syscall
321 -       data8 ia64_ni_syscall
322 -       data8 ia64_ni_syscall                   // 1225
323 -       data8 ia64_ni_syscall
324 -       data8 ia64_ni_syscall
325 -       data8 ia64_ni_syscall
326 +       data8 sys_setxattr
327 +       data8 sys_lsetxattr
328 +       data8 sys_fsetxattr
329 +       data8 sys_getxattr                      // 1220
330 +       data8 sys_lgetxattr
331 +       data8 sys_fgetxattr
332 +       data8 sys_listxattr
333 +       data8 sys_llistxattr
334 +       data8 sys_flistxattr                    // 1225
335 +       data8 sys_removexattr
336 +       data8 sys_lremovexattr
337 +       data8 sys_fremovexattr
338         data8 ia64_ni_syscall
339         data8 ia64_ni_syscall                   // 1230
340         data8 ia64_ni_syscall
341 Index: linux-2.4.19-pre1/arch/m68k/defconfig
342 ===================================================================
343 --- linux-2.4.19-pre1.orig/arch/m68k/defconfig  2000-06-19 23:56:08.000000000 +0400
344 +++ linux-2.4.19-pre1/arch/m68k/defconfig       2004-01-14 01:11:49.000000000 +0300
345 @@ -1,6 +1,13 @@
346  #
347  # Automatically generated make config: don't edit
348  #
349 +CONFIG_EXT3_FS_XATTR=y
350 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
351 +# CONFIG_EXT3_FS_XATTR_USER is not set
352 +# CONFIG_EXT2_FS_XATTR is not set
353 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
354 +# CONFIG_EXT2_FS_XATTR_USER is not set
355 +# CONFIG_FS_MBCACHE is not set
356  CONFIG_UID16=y
357  
358  #
359 Index: linux-2.4.19-pre1/arch/mips/defconfig
360 ===================================================================
361 --- linux-2.4.19-pre1.orig/arch/mips/defconfig  2001-09-09 21:43:02.000000000 +0400
362 +++ linux-2.4.19-pre1/arch/mips/defconfig       2004-01-14 01:11:49.000000000 +0300
363 @@ -1,6 +1,13 @@
364  #
365  # Automatically generated make config: don't edit
366  #
367 +CONFIG_EXT3_FS_XATTR=y
368 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
369 +# CONFIG_EXT3_FS_XATTR_USER is not set
370 +# CONFIG_EXT2_FS_XATTR is not set
371 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
372 +# CONFIG_EXT2_FS_XATTR_USER is not set
373 +# CONFIG_FS_MBCACHE is not set
374  CONFIG_MIPS=y
375  # CONFIG_SMP is not set
376  
377 Index: linux-2.4.19-pre1/arch/mips64/defconfig
378 ===================================================================
379 --- linux-2.4.19-pre1.orig/arch/mips64/defconfig        2001-09-09 21:43:02.000000000 +0400
380 +++ linux-2.4.19-pre1/arch/mips64/defconfig     2004-01-14 01:11:49.000000000 +0300
381 @@ -1,6 +1,13 @@
382  #
383  # Automatically generated make config: don't edit
384  #
385 +CONFIG_EXT3_FS_XATTR=y
386 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
387 +# CONFIG_EXT3_FS_XATTR_USER is not set
388 +# CONFIG_EXT2_FS_XATTR is not set
389 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
390 +# CONFIG_EXT2_FS_XATTR_USER is not set
391 +# CONFIG_FS_MBCACHE is not set
392  
393  #
394  # Code maturity level options
395 Index: linux-2.4.19-pre1/arch/ppc/defconfig
396 ===================================================================
397 --- linux-2.4.19-pre1.orig/arch/ppc/defconfig   2004-01-14 01:10:36.000000000 +0300
398 +++ linux-2.4.19-pre1/arch/ppc/defconfig        2004-01-14 01:11:49.000000000 +0300
399 @@ -1,6 +1,13 @@
400  #
401  # Automatically generated make config: don't edit
402  #
403 +CONFIG_EXT3_FS_XATTR=y
404 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
405 +# CONFIG_EXT3_FS_XATTR_USER is not set
406 +# CONFIG_EXT2_FS_XATTR is not set
407 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
408 +# CONFIG_EXT2_FS_XATTR_USER is not set
409 +# CONFIG_FS_MBCACHE is not set
410  # CONFIG_UID16 is not set
411  # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
412  CONFIG_RWSEM_XCHGADD_ALGORITHM=y
413 Index: linux-2.4.19-pre1/arch/s390/defconfig
414 ===================================================================
415 --- linux-2.4.19-pre1.orig/arch/s390/defconfig  2004-01-14 01:10:36.000000000 +0300
416 +++ linux-2.4.19-pre1/arch/s390/defconfig       2004-01-14 01:11:49.000000000 +0300
417 @@ -1,6 +1,13 @@
418  #
419  # Automatically generated make config: don't edit
420  #
421 +CONFIG_EXT3_FS_XATTR=y
422 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
423 +# CONFIG_EXT3_FS_XATTR_USER is not set
424 +# CONFIG_EXT2_FS_XATTR is not set
425 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
426 +# CONFIG_EXT2_FS_XATTR_USER is not set
427 +# CONFIG_FS_MBCACHE is not set
428  # CONFIG_ISA is not set
429  # CONFIG_EISA is not set
430  # CONFIG_MCA is not set
431 Index: linux-2.4.19-pre1/arch/s390/kernel/entry.S
432 ===================================================================
433 --- linux-2.4.19-pre1.orig/arch/s390/kernel/entry.S     2004-01-14 01:10:36.000000000 +0300
434 +++ linux-2.4.19-pre1/arch/s390/kernel/entry.S  2004-01-14 01:11:49.000000000 +0300
435 @@ -599,8 +599,19 @@
436          .long  sys_fcntl64 
437         .long  sys_ni_syscall            /* 222 - reserved for posix_acl */
438         .long  sys_ni_syscall            /* 223 - reserved for posix_acl */
439 -       .long  sys_ni_syscall            /* 224 - reserved for posix_acl */
440 -       .rept  255-224
441 +       .long  sys_setxattr
442 +       .long  sys_lsetxattr            /* 225 */
443 +       .long  sys_fsetxattr
444 +       .long  sys_getxattr
445 +       .long  sys_lgetxattr
446 +       .long  sys_fgetxattr
447 +       .long  sys_listxattr            /* 230 */
448 +       .long  sys_llistxattr
449 +       .long  sys_flistxattr
450 +       .long  sys_removexattr
451 +       .long  sys_lremovexattr
452 +       .long  sys_fremovexattr         /* 235 */
453 +       .rept  255-235
454         .long  sys_ni_syscall
455         .endr
456  
457 Index: linux-2.4.19-pre1/arch/s390x/defconfig
458 ===================================================================
459 --- linux-2.4.19-pre1.orig/arch/s390x/defconfig 2004-01-14 01:10:36.000000000 +0300
460 +++ linux-2.4.19-pre1/arch/s390x/defconfig      2004-01-14 01:11:49.000000000 +0300
461 @@ -1,6 +1,13 @@
462  #
463  # Automatically generated make config: don't edit
464  #
465 +CONFIG_EXT3_FS_XATTR=y
466 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
467 +# CONFIG_EXT3_FS_XATTR_USER is not set
468 +# CONFIG_EXT2_FS_XATTR is not set
469 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
470 +# CONFIG_EXT2_FS_XATTR_USER is not set
471 +# CONFIG_FS_MBCACHE is not set
472  # CONFIG_ISA is not set
473  # CONFIG_EISA is not set
474  # CONFIG_MCA is not set
475 Index: linux-2.4.19-pre1/arch/s390x/kernel/entry.S
476 ===================================================================
477 --- linux-2.4.19-pre1.orig/arch/s390x/kernel/entry.S    2004-01-14 01:10:36.000000000 +0300
478 +++ linux-2.4.19-pre1/arch/s390x/kernel/entry.S 2004-01-14 01:11:49.000000000 +0300
479 @@ -632,8 +632,19 @@
480         .long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
481         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 222 - reserved for posix_acl */
482         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 223 - reserved for posix_acl */
483 -       .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for posix_acl */
484 -        .rept  255-224
485 +       .long  SYSCALL(sys_setxattr,sys32_setxattr_wrapper)
486 +       .long  SYSCALL(sys_lsetxattr,sys32_lsetxattr_wrapper)   /* 225 */
487 +       .long  SYSCALL(sys_fsetxattr,sys32_fsetxattr_wrapper)
488 +       .long  SYSCALL(sys_getxattr,sys32_getxattr_wrapper)
489 +       .long  SYSCALL(sys_lgetxattr,sys32_lgetxattr_wrapper)
490 +       .long  SYSCALL(sys_fgetxattr,sys32_fgetxattr_wrapper)
491 +       .long  SYSCALL(sys_listxattr,sys32_listxattr_wrapper)   /* 230 */
492 +       .long  SYSCALL(sys_llistxattr,sys32_llistxattr_wrapper)
493 +       .long  SYSCALL(sys_flistxattr,sys32_flistxattr_wrapper)
494 +       .long  SYSCALL(sys_removexattr,sys32_removexattr_wrapper)
495 +       .long  SYSCALL(sys_lremovexattr,sys32_lremovexattr_wrapper)
496 +       .long  SYSCALL(sys_fremovexattr,sys32_fremovexattr_wrapper)/* 235 */
497 +        .rept  255-235
498         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
499         .endr
500  
501 Index: linux-2.4.19-pre1/arch/s390x/kernel/wrapper32.S
502 ===================================================================
503 --- linux-2.4.19-pre1.orig/arch/s390x/kernel/wrapper32.S        2004-01-14 01:10:36.000000000 +0300
504 +++ linux-2.4.19-pre1/arch/s390x/kernel/wrapper32.S     2004-01-14 01:11:49.000000000 +0300
505 @@ -1091,3 +1091,95 @@
506         llgtr   %r3,%r3                 # struct stat64 *
507         llgfr   %r4,%r4                 # long
508         jg      sys32_fstat64           # branch to system call
509 +
510 +       .globl  sys32_setxattr_wrapper
511 +sys32_setxattr_wrapper:
512 +       llgtr   %r2,%r2                 # char *
513 +       llgtr   %r3,%r3                 # char *
514 +       llgtr   %r4,%r4                 # void *
515 +       llgfr   %r5,%r5                 # size_t
516 +       lgfr    %r6,%r6                 # int
517 +       jg      sys_setxattr
518 +
519 +       .globl  sys32_lsetxattr_wrapper
520 +sys32_lsetxattr_wrapper:
521 +       llgtr   %r2,%r2                 # char *
522 +       llgtr   %r3,%r3                 # char *
523 +       llgtr   %r4,%r4                 # void *
524 +       llgfr   %r5,%r5                 # size_t
525 +       lgfr    %r6,%r6                 # int
526 +       jg      sys_lsetxattr
527 +
528 +       .globl  sys32_fsetxattr_wrapper
529 +sys32_fsetxattr_wrapper:
530 +       lgfr    %r2,%r2                 # int
531 +       llgtr   %r3,%r3                 # char *
532 +       llgtr   %r4,%r4                 # void *
533 +       llgfr   %r5,%r5                 # size_t
534 +       lgfr    %r6,%r6                 # int
535 +       jg      sys_fsetxattr
536 +
537 +       .globl  sys32_getxattr_wrapper
538 +sys32_getxattr_wrapper:
539 +       llgtr   %r2,%r2                 # char *
540 +       llgtr   %r3,%r3                 # char *
541 +       llgtr   %r4,%r4                 # void *
542 +       llgfr   %r5,%r5                 # size_t
543 +       jg      sys_getxattr
544 +
545 +       .globl  sys32_lgetxattr_wrapper
546 +sys32_lgetxattr_wrapper:
547 +       llgtr   %r2,%r2                 # char *
548 +       llgtr   %r3,%r3                 # char *
549 +       llgtr   %r4,%r4                 # void *
550 +       llgfr   %r5,%r5                 # size_t
551 +       jg      sys_lgetxattr
552 +
553 +       .globl  sys32_fgetxattr_wrapper
554 +sys32_fgetxattr_wrapper:
555 +       lgfr    %r2,%r2                 # int
556 +       llgtr   %r3,%r3                 # char *
557 +       llgtr   %r4,%r4                 # void *
558 +       llgfr   %r5,%r5                 # size_t
559 +       jg      sys_fgetxattr
560 +
561 +       .globl  sys32_listxattr_wrapper
562 +sys32_listxattr_wrapper:
563 +       llgtr   %r2,%r2                 # char *
564 +       llgtr   %r3,%r3                 # char *
565 +       llgfr   %r4,%r4                 # size_t
566 +       jg      sys_listxattr
567 +
568 +       .globl  sys32_llistxattr_wrapper
569 +sys32_llistxattr_wrapper:
570 +       llgtr   %r2,%r2                 # char *
571 +       llgtr   %r3,%r3                 # char *
572 +       llgfr   %r4,%r4                 # size_t
573 +       jg      sys_llistxattr
574 +
575 +       .globl  sys32_flistxattr_wrapper
576 +sys32_flistxattr_wrapper:
577 +       lgfr    %r2,%r2                 # int
578 +       llgtr   %r3,%r3                 # char *
579 +       llgfr   %r4,%r4                 # size_t
580 +       jg      sys_flistxattr
581 +
582 +       .globl  sys32_removexattr_wrapper
583 +sys32_removexattr_wrapper:
584 +       llgtr   %r2,%r2                 # char *
585 +       llgtr   %r3,%r3                 # char *
586 +       jg      sys_removexattr
587 +
588 +       .globl  sys32_lremovexattr_wrapper
589 +sys32_lremovexattr_wrapper:
590 +       llgtr   %r2,%r2                 # char *
591 +       llgtr   %r3,%r3                 # char *
592 +       jg      sys_lremovexattr
593 +
594 +       .globl  sys32_fremovexattr_wrapper
595 +sys32_fremovexattr_wrapper:
596 +       lgfr    %r2,%r2                 # int
597 +       llgtr   %r3,%r3                 # char *
598 +       jg      sys_fremovexattr
599 +
600 +
601 Index: linux-2.4.19-pre1/arch/sparc/defconfig
602 ===================================================================
603 --- linux-2.4.19-pre1.orig/arch/sparc/defconfig 2004-01-14 01:10:36.000000000 +0300
604 +++ linux-2.4.19-pre1/arch/sparc/defconfig      2004-01-14 01:11:49.000000000 +0300
605 @@ -1,6 +1,13 @@
606  #
607  # Automatically generated make config: don't edit
608  #
609 +CONFIG_EXT3_FS_XATTR=y
610 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
611 +# CONFIG_EXT3_FS_XATTR_USER is not set
612 +# CONFIG_EXT2_FS_XATTR is not set
613 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
614 +# CONFIG_EXT2_FS_XATTR_USER is not set
615 +# CONFIG_FS_MBCACHE is not set
616  CONFIG_UID16=y
617  CONFIG_HIGHMEM=y
618  
619 Index: linux-2.4.19-pre1/arch/sparc/kernel/systbls.S
620 ===================================================================
621 --- linux-2.4.19-pre1.orig/arch/sparc/kernel/systbls.S  2001-10-21 21:36:54.000000000 +0400
622 +++ linux-2.4.19-pre1/arch/sparc/kernel/systbls.S       2004-01-14 01:11:49.000000000 +0300
623 @@ -51,11 +51,11 @@
624  /*150*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
625  /*155*/        .long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
626  /*160*/        .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
627 -/*165*/        .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
628 -/*170*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
629 -/*175*/        .long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
630 -/*180*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
631 -/*185*/        .long sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
632 +/*165*/        .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
633 +/*170*/        .long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
634 +/*175*/        .long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
635 +/*180*/        .long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_query_module
636 +/*185*/        .long sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sys_newuname
637  /*190*/        .long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
638  /*195*/        .long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
639  /*200*/        .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
640 Index: linux-2.4.19-pre1/arch/sparc64/defconfig
641 ===================================================================
642 --- linux-2.4.19-pre1.orig/arch/sparc64/defconfig       2004-01-14 01:10:36.000000000 +0300
643 +++ linux-2.4.19-pre1/arch/sparc64/defconfig    2004-01-14 01:11:49.000000000 +0300
644 @@ -1,6 +1,13 @@
645  #
646  # Automatically generated make config: don't edit
647  #
648 +CONFIG_EXT3_FS_XATTR=y
649 +# CONFIG_EXT3_FS_XATTR_SHARING is not set
650 +# CONFIG_EXT3_FS_XATTR_USER is not set
651 +# CONFIG_EXT2_FS_XATTR is not set
652 +# CONFIG_EXT2_FS_XATTR_SHARING is not set
653 +# CONFIG_EXT2_FS_XATTR_USER is not set
654 +# CONFIG_FS_MBCACHE is not set
655  
656  #
657  # Code maturity level options
658 Index: linux-2.4.19-pre1/arch/sparc64/kernel/systbls.S
659 ===================================================================
660 --- linux-2.4.19-pre1.orig/arch/sparc64/kernel/systbls.S        2001-10-21 21:36:54.000000000 +0400
661 +++ linux-2.4.19-pre1/arch/sparc64/kernel/systbls.S     2004-01-14 01:11:49.000000000 +0300
662 @@ -52,11 +52,11 @@
663  /*150*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
664         .word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
665  /*160*/        .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
666 -       .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
667 -/*170*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
668 -       .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
669 -/*180*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
670 -       .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
671 +       .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
672 +/*170*/        .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
673 +       .word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
674 +/*180*/        .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
675 +       .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
676  /*190*/        .word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
677         .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
678  /*200*/        .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
679 @@ -111,11 +111,11 @@
680  /*150*/        .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
681         .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
682  /*160*/        .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
683 -       .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
684 -/*170*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
685 -       .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
686 -/*180*/        .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
687 -       .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sparc64_newuname
688 +       .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
689 +/*170*/        .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
690 +       .word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
691 +/*180*/        .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_query_module
692 +       .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
693  /*190*/        .word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
694         .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
695  /*200*/        .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
696 Index: linux-2.4.19-pre1/fs/Config.in
697 ===================================================================
698 --- linux-2.4.19-pre1.orig/fs/Config.in 2004-01-14 01:10:37.000000000 +0300
699 +++ linux-2.4.19-pre1/fs/Config.in      2004-01-14 01:11:49.000000000 +0300
700 @@ -22,6 +22,11 @@
701  dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
702  
703  tristate 'Ext3 journalling file system support (EXPERIMENTAL)' CONFIG_EXT3_FS
704 +dep_mbool '  Ext3 extended attributes' CONFIG_EXT3_FS_XATTR $CONFIG_EXT3_FS
705 +dep_bool '    Ext3 extended attribute block sharing' \
706 +    CONFIG_EXT3_FS_XATTR_SHARING $CONFIG_EXT3_FS_XATTR
707 +dep_bool '    Ext3 extended user attributes' \
708 +    CONFIG_EXT3_FS_XATTR_USER $CONFIG_EXT3_FS_XATTR
709  # CONFIG_JBD could be its own option (even modular), but until there are
710  # other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS
711  # dep_tristate '  Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS
712 @@ -77,6 +82,11 @@
713  tristate 'ROM file system support' CONFIG_ROMFS_FS
714  
715  tristate 'Second extended fs support' CONFIG_EXT2_FS
716 +dep_mbool '  Ext2 extended attributes' CONFIG_EXT2_FS_XATTR $CONFIG_EXT2_FS
717 +dep_bool '    Ext2 extended attribute block sharing' \
718 +    CONFIG_EXT2_FS_XATTR_SHARING $CONFIG_EXT2_FS_XATTR
719 +dep_bool '    Ext2 extended user attributes' \
720 +    CONFIG_EXT2_FS_XATTR_USER $CONFIG_EXT2_FS_XATTR
721  
722  tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS
723  
724 @@ -156,6 +166,10 @@
725    fi
726  fi
727  
728 +# Meta block cache for Extended Attributes (ext2/ext3)
729 +#tristate 'Meta block cache' CONFIG_FS_MBCACHE
730 +define_tristate CONFIG_FS_MBCACHE y 
731 +
732  mainmenu_option next_comment
733  comment 'Partition Types'
734  source fs/partitions/Config.in
735 Index: linux-2.4.19-pre1/fs/Makefile
736 ===================================================================
737 --- linux-2.4.19-pre1.orig/fs/Makefile  2004-01-14 01:11:49.000000000 +0300
738 +++ linux-2.4.19-pre1/fs/Makefile       2004-01-14 01:11:49.000000000 +0300
739 @@ -14,7 +14,7 @@
740                 super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
741                 fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
742                 dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
743 -               filesystems.o namespace.o seq_file.o
744 +               filesystems.o namespace.o seq_file.o xattr.o
745  
746  ifeq ($(CONFIG_QUOTA),y)
747  obj-y += dquot.o
748 @@ -78,6 +78,9 @@
749  
750  obj-$(CONFIG_BINFMT_ELF)       += binfmt_elf.o
751  
752 +export-objs += mbcache.o
753 +obj-$(CONFIG_FS_MBCACHE)       += mbcache.o
754 +
755  # persistent filesystems
756  obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
757  
758 Index: linux-2.4.19-pre1/fs/ext2/Makefile
759 ===================================================================
760 --- linux-2.4.19-pre1.orig/fs/ext2/Makefile     2001-10-11 19:05:18.000000000 +0400
761 +++ linux-2.4.19-pre1/fs/ext2/Makefile  2004-01-14 01:11:49.000000000 +0300
762 @@ -13,4 +13,8 @@
763                 ioctl.o namei.o super.o symlink.o
764  obj-m    := $(O_TARGET)
765  
766 +export-objs += xattr.o
767 +obj-$(CONFIG_EXT2_FS_XATTR) += xattr.o
768 +obj-$(CONFIG_EXT2_FS_XATTR_USER) += xattr_user.o
769 +
770  include $(TOPDIR)/Rules.make
771 Index: linux-2.4.19-pre1/fs/ext2/file.c
772 ===================================================================
773 --- linux-2.4.19-pre1.orig/fs/ext2/file.c       2001-10-11 19:05:18.000000000 +0400
774 +++ linux-2.4.19-pre1/fs/ext2/file.c    2004-01-14 01:11:49.000000000 +0300
775 @@ -20,6 +20,7 @@
776  
777  #include <linux/fs.h>
778  #include <linux/ext2_fs.h>
779 +#include <linux/ext2_xattr.h>
780  #include <linux/sched.h>
781  
782  /*
783 @@ -51,4 +52,8 @@
784  
785  struct inode_operations ext2_file_inode_operations = {
786         truncate:       ext2_truncate,
787 +       setxattr:       ext2_setxattr,
788 +       getxattr:       ext2_getxattr,
789 +       listxattr:      ext2_listxattr,
790 +       removexattr:    ext2_removexattr,
791  };
792 Index: linux-2.4.19-pre1/fs/ext2/ialloc.c
793 ===================================================================
794 --- linux-2.4.19-pre1.orig/fs/ext2/ialloc.c     2004-01-14 01:10:37.000000000 +0300
795 +++ linux-2.4.19-pre1/fs/ext2/ialloc.c  2004-01-14 01:11:49.000000000 +0300
796 @@ -15,6 +15,7 @@
797  #include <linux/config.h>
798  #include <linux/fs.h>
799  #include <linux/ext2_fs.h>
800 +#include <linux/ext2_xattr.h>
801  #include <linux/locks.h>
802  #include <linux/quotaops.h>
803  
804 @@ -167,6 +168,7 @@
805          */
806         if (!is_bad_inode(inode)) {
807                 /* Quota is already initialized in iput() */
808 +               ext2_xattr_delete_inode(inode);
809                 DQUOT_FREE_INODE(inode);
810                 DQUOT_DROP(inode);
811         }
812 Index: linux-2.4.19-pre1/fs/ext2/inode.c
813 ===================================================================
814 --- linux-2.4.19-pre1.orig/fs/ext2/inode.c      2004-01-14 01:10:37.000000000 +0300
815 +++ linux-2.4.19-pre1/fs/ext2/inode.c   2004-01-14 01:11:49.000000000 +0300
816 @@ -39,6 +39,18 @@
817  static int ext2_update_inode(struct inode * inode, int do_sync);
818  
819  /*
820 + * Test whether an inode is a fast symlink.
821 + */
822 +static inline int ext2_inode_is_fast_symlink(struct inode *inode)
823 +{
824 +       int ea_blocks = inode->u.ext2_i.i_file_acl ?
825 +               (inode->i_sb->s_blocksize >> 9) : 0;
826 +
827 +       return (S_ISLNK(inode->i_mode) &&
828 +               inode->i_blocks - ea_blocks == 0);
829 +}
830 +
831 +/*
832   * Called at each iput()
833   */
834  void ext2_put_inode (struct inode * inode)
835 @@ -53,9 +65,7 @@
836  {
837         lock_kernel();
838  
839 -       if (is_bad_inode(inode) ||
840 -           inode->i_ino == EXT2_ACL_IDX_INO ||
841 -           inode->i_ino == EXT2_ACL_DATA_INO)
842 +       if (is_bad_inode(inode))
843                 goto no_delete;
844         inode->u.ext2_i.i_dtime = CURRENT_TIME;
845         mark_inode_dirty(inode);
846 @@ -800,6 +810,8 @@
847         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
848             S_ISLNK(inode->i_mode)))
849                 return;
850 +       if (ext2_inode_is_fast_symlink(inode))
851 +               return;
852         if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
853                 return;
854  
855 @@ -889,8 +901,7 @@
856         unsigned long offset;
857         struct ext2_group_desc * gdp;
858  
859 -       if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
860 -            inode->i_ino != EXT2_ACL_DATA_INO &&
861 +       if ((inode->i_ino != EXT2_ROOT_INO &&
862              inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
863             inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {
864                 ext2_error (inode->i_sb, "ext2_read_inode",
865 @@ -975,10 +986,7 @@
866         for (block = 0; block < EXT2_N_BLOCKS; block++)
867                 inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
868  
869 -       if (inode->i_ino == EXT2_ACL_IDX_INO ||
870 -           inode->i_ino == EXT2_ACL_DATA_INO)
871 -               /* Nothing to do */ ;
872 -       else if (S_ISREG(inode->i_mode)) {
873 +       if (S_ISREG(inode->i_mode)) {
874                 inode->i_op = &ext2_file_inode_operations;
875                 inode->i_fop = &ext2_file_operations;
876                 inode->i_mapping->a_ops = &ext2_aops;
877 @@ -987,15 +995,17 @@
878                 inode->i_fop = &ext2_dir_operations;
879                 inode->i_mapping->a_ops = &ext2_aops;
880         } else if (S_ISLNK(inode->i_mode)) {
881 -               if (!inode->i_blocks)
882 +               if (ext2_inode_is_fast_symlink(inode))
883                         inode->i_op = &ext2_fast_symlink_inode_operations;
884                 else {
885 -                       inode->i_op = &page_symlink_inode_operations;
886 +                       inode->i_op = &ext2_symlink_inode_operations;
887                         inode->i_mapping->a_ops = &ext2_aops;
888                 }
889 -       } else 
890 +       } else {
891 +               inode->i_op = &ext2_special_inode_operations;
892                 init_special_inode(inode, inode->i_mode,
893                                    le32_to_cpu(raw_inode->i_block[0]));
894 +       }
895         brelse (bh);
896         inode->i_attr_flags = 0;
897         if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
898 Index: linux-2.4.19-pre1/fs/ext2/namei.c
899 ===================================================================
900 --- linux-2.4.19-pre1.orig/fs/ext2/namei.c      2001-10-04 09:57:36.000000000 +0400
901 +++ linux-2.4.19-pre1/fs/ext2/namei.c   2004-01-14 01:11:49.000000000 +0300
902 @@ -31,6 +31,7 @@
903  
904  #include <linux/fs.h>
905  #include <linux/ext2_fs.h>
906 +#include <linux/ext2_xattr.h>
907  #include <linux/pagemap.h>
908  
909  /*
910 @@ -136,7 +137,7 @@
911  
912         if (l > sizeof (inode->u.ext2_i.i_data)) {
913                 /* slow symlink */
914 -               inode->i_op = &page_symlink_inode_operations;
915 +               inode->i_op = &ext2_symlink_inode_operations;
916                 inode->i_mapping->a_ops = &ext2_aops;
917                 err = block_symlink(inode, symname, l);
918                 if (err)
919 @@ -345,4 +346,15 @@
920         rmdir:          ext2_rmdir,
921         mknod:          ext2_mknod,
922         rename:         ext2_rename,
923 +       setxattr:       ext2_setxattr,
924 +       getxattr:       ext2_getxattr,
925 +       listxattr:      ext2_listxattr,
926 +       removexattr:    ext2_removexattr,
927 +};
928 +
929 +struct inode_operations ext2_special_inode_operations = {
930 +       setxattr:       ext2_setxattr,
931 +       getxattr:       ext2_getxattr,
932 +       listxattr:      ext2_listxattr,
933 +       removexattr:    ext2_removexattr,
934  };
935 Index: linux-2.4.19-pre1/fs/ext2/super.c
936 ===================================================================
937 --- linux-2.4.19-pre1.orig/fs/ext2/super.c      2004-01-14 01:10:37.000000000 +0300
938 +++ linux-2.4.19-pre1/fs/ext2/super.c   2004-01-14 01:11:49.000000000 +0300
939 @@ -21,6 +21,7 @@
940  #include <linux/string.h>
941  #include <linux/fs.h>
942  #include <linux/ext2_fs.h>
943 +#include <linux/ext2_xattr.h>
944  #include <linux/slab.h>
945  #include <linux/init.h>
946  #include <linux/locks.h>
947 @@ -125,6 +126,7 @@
948         int db_count;
949         int i;
950  
951 +       ext2_xattr_put_super(sb);
952         if (!(sb->s_flags & MS_RDONLY)) {
953                 struct ext2_super_block *es = EXT2_SB(sb)->s_es;
954  
955 @@ -175,6 +177,13 @@
956              this_char = strtok (NULL, ",")) {
957                 if ((value = strchr (this_char, '=')) != NULL)
958                         *value++ = 0;
959 +#ifdef CONFIG_EXT2_FS_XATTR_USER
960 +               if (!strcmp (this_char, "user_xattr"))
961 +                       set_opt (*mount_options, XATTR_USER);
962 +               else if (!strcmp (this_char, "nouser_xattr"))
963 +                       clear_opt (*mount_options, XATTR_USER);
964 +               else
965 +#endif
966                 if (!strcmp (this_char, "bsddf"))
967                         clear_opt (*mount_options, MINIX_DF);
968                 else if (!strcmp (this_char, "nouid32")) {
969 @@ -424,6 +433,9 @@
970             blocksize = BLOCK_SIZE;
971  
972         sb->u.ext2_sb.s_mount_opt = 0;
973 +#ifdef CONFIG_EXT2_FS_XATTR_USER
974 +       /* set_opt (sb->u.ext2_sb.s_mount_opt, XATTR_USER); */
975 +#endif
976         if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
977             &sb->u.ext2_sb.s_mount_opt)) {
978                 return NULL;
979 @@ -810,12 +822,27 @@
980  
981  static int __init init_ext2_fs(void)
982  {
983 -        return register_filesystem(&ext2_fs_type);
984 +       int error = init_ext2_xattr();
985 +       if (error)
986 +               return error;
987 +       error = init_ext2_xattr_user();
988 +       if (error)
989 +               goto fail;
990 +       error = register_filesystem(&ext2_fs_type);
991 +       if (!error)
992 +               return 0;
993 +
994 +       exit_ext2_xattr_user();
995 +fail:
996 +       exit_ext2_xattr();
997 +       return error;
998  }
999  
1000  static void __exit exit_ext2_fs(void)
1001  {
1002         unregister_filesystem(&ext2_fs_type);
1003 +       exit_ext2_xattr_user();
1004 +       exit_ext2_xattr();
1005  }
1006  
1007  EXPORT_NO_SYMBOLS;
1008 Index: linux-2.4.19-pre1/fs/ext2/symlink.c
1009 ===================================================================
1010 --- linux-2.4.19-pre1.orig/fs/ext2/symlink.c    2000-09-28 00:41:33.000000000 +0400
1011 +++ linux-2.4.19-pre1/fs/ext2/symlink.c 2004-01-14 01:11:49.000000000 +0300
1012 @@ -19,6 +19,7 @@
1013  
1014  #include <linux/fs.h>
1015  #include <linux/ext2_fs.h>
1016 +#include <linux/ext2_xattr.h>
1017  
1018  static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
1019  {
1020 @@ -32,7 +33,20 @@
1021         return vfs_follow_link(nd, s);
1022  }
1023  
1024 +struct inode_operations ext2_symlink_inode_operations = {
1025 +       readlink:       page_readlink,
1026 +       follow_link:    page_follow_link,
1027 +       setxattr:       ext2_setxattr,
1028 +       getxattr:       ext2_getxattr,
1029 +       listxattr:      ext2_listxattr,
1030 +       removexattr:    ext2_removexattr,
1031 +};
1032 +
1033  struct inode_operations ext2_fast_symlink_inode_operations = {
1034         readlink:       ext2_readlink,
1035         follow_link:    ext2_follow_link,
1036 +       setxattr:       ext2_setxattr,
1037 +       getxattr:       ext2_getxattr,
1038 +       listxattr:      ext2_listxattr,
1039 +       removexattr:    ext2_removexattr,
1040  };
1041 Index: linux-2.4.19-pre1/fs/ext2/xattr.c
1042 ===================================================================
1043 --- linux-2.4.19-pre1.orig/fs/ext2/xattr.c      2003-01-30 13:24:37.000000000 +0300
1044 +++ linux-2.4.19-pre1/fs/ext2/xattr.c   2004-01-14 01:11:49.000000000 +0300
1045 @@ -0,0 +1,1212 @@
1046 +/*
1047 + * linux/fs/ext2/xattr.c
1048 + *
1049 + * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
1050 + *
1051 + * Fix by Harrison Xing <harrison@mountainviewdata.com>.
1052 + * Extended attributes for symlinks and special files added per
1053 + *  suggestion of Luka Renko <luka.renko@hermes.si>.
1054 + */
1055 +
1056 +/*
1057 + * Extended attributes are stored on disk blocks allocated outside of
1058 + * any inode. The i_file_acl field is then made to point to this allocated
1059 + * block. If all extended attributes of an inode are identical, these
1060 + * inodes may share the same extended attribute block. Such situations
1061 + * are automatically detected by keeping a cache of recent attribute block
1062 + * numbers and hashes over the block's contents in memory.
1063 + *
1064 + *
1065 + * Extended attribute block layout:
1066 + *
1067 + *   +------------------+
1068 + *   | header           |
1069 + *   | entry 1          | |
1070 + *   | entry 2          | | growing downwards
1071 + *   | entry 3          | v
1072 + *   | four null bytes  |
1073 + *   | . . .            |
1074 + *   | value 1          | ^
1075 + *   | value 3          | | growing upwards
1076 + *   | value 2          | |
1077 + *   +------------------+
1078 + *
1079 + * The block header is followed by multiple entry descriptors. These entry
1080 + * descriptors are variable in size, and alligned to EXT2_XATTR_PAD
1081 + * byte boundaries. The entry descriptors are sorted by attribute name,
1082 + * so that two extended attribute blocks can be compared efficiently.
1083 + *
1084 + * Attribute values are aligned to the end of the block, stored in
1085 + * no specific order. They are also padded to EXT2_XATTR_PAD byte
1086 + * boundaries. No additional gaps are left between them.
1087 + *
1088 + * Locking strategy
1089 + * ----------------
1090 + * The VFS already holds the BKL and the inode->i_sem semaphore when any of
1091 + * the xattr inode operations are called, so we are guaranteed that only one
1092 + * processes accesses extended attributes of an inode at any time.
1093 + *
1094 + * For writing we also grab the ext2_xattr_sem semaphore. This ensures that
1095 + * only a single process is modifying an extended attribute block, even
1096 + * if the block is shared among inodes.
1097 + *
1098 + * Note for porting to 2.5
1099 + * -----------------------
1100 + * The BKL will no longer be held in the xattr inode operations.
1101 + */
1102 +
1103 +#include <linux/module.h>
1104 +#include <linux/locks.h>
1105 +#include <linux/slab.h>
1106 +#include <linux/fs.h>
1107 +#include <linux/ext2_fs.h>
1108 +#include <linux/ext2_xattr.h>
1109 +#include <linux/mbcache.h>
1110 +#include <linux/quotaops.h>
1111 +#include <asm/semaphore.h>
1112 +#include <linux/compatmac.h>
1113 +
1114 +/* These symbols may be needed by a module. */
1115 +EXPORT_SYMBOL(ext2_xattr_register);
1116 +EXPORT_SYMBOL(ext2_xattr_unregister);
1117 +EXPORT_SYMBOL(ext2_xattr_get);
1118 +EXPORT_SYMBOL(ext2_xattr_list);
1119 +EXPORT_SYMBOL(ext2_xattr_set);
1120 +
1121 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
1122 +# define mark_buffer_dirty(bh) mark_buffer_dirty(bh, 1)
1123 +#endif
1124 +
1125 +#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data))
1126 +#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr))
1127 +#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
1128 +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
1129 +
1130 +#ifdef EXT2_XATTR_DEBUG
1131 +# define ea_idebug(inode, f...) do { \
1132 +               printk(KERN_DEBUG "inode %s:%ld: ", \
1133 +                       kdevname(inode->i_dev), inode->i_ino); \
1134 +               printk(f); \
1135 +               printk("\n"); \
1136 +       } while (0)
1137 +# define ea_bdebug(bh, f...) do { \
1138 +               printk(KERN_DEBUG "block %s:%ld: ", \
1139 +                       kdevname(bh->b_dev), bh->b_blocknr); \
1140 +               printk(f); \
1141 +               printk("\n"); \
1142 +       } while (0)
1143 +#else
1144 +# define ea_idebug(f...)
1145 +# define ea_bdebug(f...)
1146 +#endif
1147 +
1148 +static int ext2_xattr_set2(struct inode *, struct buffer_head *,
1149 +                          struct ext2_xattr_header *);
1150 +
1151 +#ifdef CONFIG_EXT2_FS_XATTR_SHARING
1152 +
1153 +static int ext2_xattr_cache_insert(struct buffer_head *);
1154 +static struct buffer_head *ext2_xattr_cache_find(struct inode *,
1155 +                                                struct ext2_xattr_header *);
1156 +static void ext2_xattr_cache_remove(struct buffer_head *);
1157 +static void ext2_xattr_rehash(struct ext2_xattr_header *,
1158 +                             struct ext2_xattr_entry *);
1159 +
1160 +static struct mb_cache *ext2_xattr_cache;
1161 +
1162 +#else
1163 +# define ext2_xattr_cache_insert(bh) 0
1164 +# define ext2_xattr_cache_find(inode, header) NULL
1165 +# define ext2_xattr_cache_remove(bh) while(0) {}
1166 +# define ext2_xattr_rehash(header, entry) while(0) {}
1167 +#endif
1168 +
1169 +/*
1170 + * If a file system does not share extended attributes among inodes,
1171 + * we should not need the ext2_xattr_sem semaphore. However, the
1172 + * filesystem may still contain shared blocks, so we always take
1173 + * the lock.
1174 + */
1175 +
1176 +DECLARE_MUTEX(ext2_xattr_sem);
1177 +
1178 +static inline int
1179 +ext2_xattr_new_block(struct inode *inode, int * errp, int force)
1180 +{
1181 +       struct super_block *sb = inode->i_sb;
1182 +       int goal = le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block) +
1183 +               EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb);
1184 +
1185 +       /* How can we enforce the allocation? */
1186 +       int block = ext2_new_block(inode, goal, 0, 0, errp);
1187 +#ifdef OLD_QUOTAS
1188 +       if (!*errp)
1189 +               inode->i_blocks += inode->i_sb->s_blocksize >> 9;
1190 +#endif
1191 +       return block;
1192 +}
1193 +
1194 +static inline int
1195 +ext2_xattr_quota_alloc(struct inode *inode, int force)
1196 +{
1197 +       /* How can we enforce the allocation? */
1198 +#ifdef OLD_QUOTAS
1199 +       int error = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1);
1200 +       if (!error)
1201 +               inode->i_blocks += inode->i_sb->s_blocksize >> 9;
1202 +#else
1203 +       int error = DQUOT_ALLOC_BLOCK(inode, 1);
1204 +#endif
1205 +       return error;
1206 +}
1207 +
1208 +#ifdef OLD_QUOTAS
1209 +
1210 +static inline void
1211 +ext2_xattr_quota_free(struct inode *inode)
1212 +{
1213 +       DQUOT_FREE_BLOCK(inode->i_sb, inode, 1);
1214 +       inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
1215 +}
1216 +
1217 +static inline void
1218 +ext2_xattr_free_block(struct inode * inode, unsigned long block)
1219 +{
1220 +       ext2_free_blocks(inode, block, 1);
1221 +       inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
1222 +}
1223 +
1224 +#else
1225 +# define ext2_xattr_quota_free(inode) \
1226 +       DQUOT_FREE_BLOCK(inode, 1)
1227 +# define ext2_xattr_free_block(inode, block) \
1228 +       ext2_free_blocks(inode, block, 1)
1229 +#endif
1230 +
1231 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
1232 +
1233 +static inline struct buffer_head *
1234 +sb_bread(struct super_block *sb, int block)
1235 +{
1236 +       return bread(sb->s_dev, block, sb->s_blocksize);
1237 +}
1238 +
1239 +static inline struct buffer_head *
1240 +sb_getblk(struct super_block *sb, int block)
1241 +{
1242 +       return getblk(sb->s_dev, block, sb->s_blocksize);
1243 +}
1244 +
1245 +#endif
1246 +
1247 +struct ext2_xattr_handler *ext2_xattr_handlers[EXT2_XATTR_INDEX_MAX];
1248 +rwlock_t ext2_handler_lock = RW_LOCK_UNLOCKED;
1249 +
1250 +int
1251 +ext2_xattr_register(int name_index, struct ext2_xattr_handler *handler)
1252 +{
1253 +       int error = -EINVAL;
1254 +
1255 +       if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) {
1256 +               write_lock(&ext2_handler_lock);
1257 +               if (!ext2_xattr_handlers[name_index-1]) {
1258 +                       ext2_xattr_handlers[name_index-1] = handler;
1259 +                       error = 0;
1260 +               }
1261 +               write_unlock(&ext2_handler_lock);
1262 +       }
1263 +       return error;
1264 +}
1265 +
1266 +void
1267 +ext2_xattr_unregister(int name_index, struct ext2_xattr_handler *handler)
1268 +{
1269 +       if (name_index > 0 || name_index <= EXT2_XATTR_INDEX_MAX) {
1270 +               write_lock(&ext2_handler_lock);
1271 +               ext2_xattr_handlers[name_index-1] = NULL;
1272 +               write_unlock(&ext2_handler_lock);
1273 +       }
1274 +}
1275 +
1276 +static inline const char *
1277 +strcmp_prefix(const char *a, const char *a_prefix)
1278 +{
1279 +       while (*a_prefix && *a == *a_prefix) {
1280 +               a++;
1281 +               a_prefix++;
1282 +       }
1283 +       return *a_prefix ? NULL : a;
1284 +}
1285 +
1286 +/*
1287 + * Decode the extended attribute name, and translate it into
1288 + * the name_index and name suffix.
1289 + */
1290 +static struct ext2_xattr_handler *
1291 +ext2_xattr_resolve_name(const char **name)
1292 +{
1293 +       struct ext2_xattr_handler *handler = NULL;
1294 +       int i;
1295 +
1296 +       if (!*name)
1297 +               return NULL;
1298 +       read_lock(&ext2_handler_lock);
1299 +       for (i=0; i<EXT2_XATTR_INDEX_MAX; i++) {
1300 +               if (ext2_xattr_handlers[i]) {
1301 +                       const char *n = strcmp_prefix(*name,
1302 +                               ext2_xattr_handlers[i]->prefix);
1303 +                       if (n) {
1304 +                               handler = ext2_xattr_handlers[i];
1305 +                               *name = n;
1306 +                               break;
1307 +                       }
1308 +               }
1309 +       }
1310 +       read_unlock(&ext2_handler_lock);
1311 +       return handler;
1312 +}
1313 +
1314 +static inline struct ext2_xattr_handler *
1315 +ext2_xattr_handler(int name_index)
1316 +{
1317 +       struct ext2_xattr_handler *handler = NULL;
1318 +       if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) {
1319 +               read_lock(&ext2_handler_lock);
1320 +               handler = ext2_xattr_handlers[name_index-1];
1321 +               read_unlock(&ext2_handler_lock);
1322 +       }
1323 +       return handler;
1324 +}
1325 +
1326 +/*
1327 + * Inode operation getxattr()
1328 + *
1329 + * dentry->d_inode->i_sem down
1330 + * BKL held [before 2.5.x]
1331 + */
1332 +ssize_t
1333 +ext2_getxattr(struct dentry *dentry, const char *name,
1334 +             void *buffer, size_t size)
1335 +{
1336 +       struct ext2_xattr_handler *handler;
1337 +       struct inode *inode = dentry->d_inode;
1338 +
1339 +       handler = ext2_xattr_resolve_name(&name);
1340 +       if (!handler)
1341 +               return -ENOTSUP;
1342 +       return handler->get(inode, name, buffer, size);
1343 +}
1344 +
1345 +/*
1346 + * Inode operation listxattr()
1347 + *
1348 + * dentry->d_inode->i_sem down
1349 + * BKL held [before 2.5.x]
1350 + */
1351 +ssize_t
1352 +ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
1353 +{
1354 +       return ext2_xattr_list(dentry->d_inode, buffer, size);
1355 +}
1356 +
1357 +/*
1358 + * Inode operation setxattr()
1359 + *
1360 + * dentry->d_inode->i_sem down
1361 + * BKL held [before 2.5.x]
1362 + */
1363 +int
1364 +ext2_setxattr(struct dentry *dentry, const char *name,
1365 +             const void *value, size_t size, int flags)
1366 +{
1367 +       struct ext2_xattr_handler *handler;
1368 +       struct inode *inode = dentry->d_inode;
1369 +
1370 +       if (size == 0)
1371 +               value = "";  /* empty EA, do not remove */
1372 +       handler = ext2_xattr_resolve_name(&name);
1373 +       if (!handler)
1374 +               return -ENOTSUP;
1375 +       return handler->set(inode, name, value, size, flags);
1376 +}
1377 +
1378 +/*
1379 + * Inode operation removexattr()
1380 + *
1381 + * dentry->d_inode->i_sem down
1382 + * BKL held [before 2.5.x]
1383 + */
1384 +int
1385 +ext2_removexattr(struct dentry *dentry, const char *name)
1386 +{
1387 +       struct ext2_xattr_handler *handler;
1388 +       struct inode *inode = dentry->d_inode;
1389 +
1390 +       handler = ext2_xattr_resolve_name(&name);
1391 +       if (!handler)
1392 +               return -ENOTSUP;
1393 +       return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
1394 +}
1395 +
1396 +/*
1397 + * ext2_xattr_get()
1398 + *
1399 + * Copy an extended attribute into the buffer
1400 + * provided, or compute the buffer size required.
1401 + * Buffer is NULL to compute the size of the buffer required.
1402 + *
1403 + * Returns a negative error number on failure, or the number of bytes
1404 + * used / required on success.
1405 + */
1406 +int
1407 +ext2_xattr_get(struct inode *inode, int name_index, const char *name,
1408 +              void *buffer, size_t buffer_size)
1409 +{
1410 +       struct buffer_head *bh = NULL;
1411 +       struct ext2_xattr_entry *entry;
1412 +       unsigned int block, size;
1413 +       char *end;
1414 +       int name_len, error;
1415 +
1416 +       ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
1417 +                 name_index, name, buffer, (long)buffer_size);
1418 +
1419 +       if (name == NULL)
1420 +               return -EINVAL;
1421 +       if (!EXT2_I(inode)->i_file_acl)
1422 +               return -ENOATTR;
1423 +       block = EXT2_I(inode)->i_file_acl;
1424 +       ea_idebug(inode, "reading block %d", block);
1425 +       bh = sb_bread(inode->i_sb, block);
1426 +       if (!bh)
1427 +               return -EIO;
1428 +       ea_bdebug(bh, "b_count=%d, refcount=%d",
1429 +               atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
1430 +       end = bh->b_data + bh->b_size;
1431 +       if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
1432 +           HDR(bh)->h_blocks != cpu_to_le32(1)) {
1433 +bad_block:     ext2_error(inode->i_sb, "ext2_xattr_get",
1434 +                       "inode %ld: bad block %d", inode->i_ino, block);
1435 +               error = -EIO;
1436 +               goto cleanup;
1437 +       }
1438 +       /* find named attribute */
1439 +       name_len = strlen(name);
1440 +
1441 +       error = -ERANGE;
1442 +       if (name_len > 255)
1443 +               goto cleanup;
1444 +       entry = FIRST_ENTRY(bh);
1445 +       while (!IS_LAST_ENTRY(entry)) {
1446 +               struct ext2_xattr_entry *next =
1447 +                       EXT2_XATTR_NEXT(entry);
1448 +               if ((char *)next >= end)
1449 +                       goto bad_block;
1450 +               if (name_index == entry->e_name_index &&
1451 +                   name_len == entry->e_name_len &&
1452 +                   memcmp(name, entry->e_name, name_len) == 0)
1453 +                       goto found;
1454 +               entry = next;
1455 +       }
1456 +       /* Check the remaining name entries */
1457 +       while (!IS_LAST_ENTRY(entry)) {
1458 +               struct ext2_xattr_entry *next =
1459 +                       EXT2_XATTR_NEXT(entry);
1460 +               if ((char *)next >= end)
1461 +                       goto bad_block;
1462 +               entry = next;
1463 +       }
1464 +       if (ext2_xattr_cache_insert(bh))
1465 +               ea_idebug(inode, "cache insert failed");
1466 +       error = -ENOATTR;
1467 +       goto cleanup;
1468 +found:
1469 +       /* check the buffer size */
1470 +       if (entry->e_value_block != 0)
1471 +               goto bad_block;
1472 +       size = le32_to_cpu(entry->e_value_size);
1473 +       if (size > inode->i_sb->s_blocksize ||
1474 +           le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
1475 +               goto bad_block;
1476 +
1477 +       if (ext2_xattr_cache_insert(bh))
1478 +               ea_idebug(inode, "cache insert failed");
1479 +       if (buffer) {
1480 +               error = -ERANGE;
1481 +               if (size > buffer_size)
1482 +                       goto cleanup;
1483 +               /* return value of attribute */
1484 +               memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
1485 +                       size);
1486 +       }
1487 +       error = size;
1488 +
1489 +cleanup:
1490 +       brelse(bh);
1491 +
1492 +       return error;
1493 +}
1494 +
1495 +/*
1496 + * ext2_xattr_list()
1497 + *
1498 + * Copy a list of attribute names into the buffer
1499 + * provided, or compute the buffer size required.
1500 + * Buffer is NULL to compute the size of the buffer required.
1501 + *
1502 + * Returns a negative error number on failure, or the number of bytes
1503 + * used / required on success.
1504 + */
1505 +int
1506 +ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
1507 +{
1508 +       struct buffer_head *bh = NULL;
1509 +       struct ext2_xattr_entry *entry;
1510 +       unsigned int block, size = 0;
1511 +       char *buf, *end;
1512 +       int error;
1513 +
1514 +       ea_idebug(inode, "buffer=%p, buffer_size=%ld",
1515 +                 buffer, (long)buffer_size);
1516 +
1517 +       if (!EXT2_I(inode)->i_file_acl)
1518 +               return 0;
1519 +       block = EXT2_I(inode)->i_file_acl;
1520 +       ea_idebug(inode, "reading block %d", block);
1521 +       bh = sb_bread(inode->i_sb, block);
1522 +       if (!bh)
1523 +               return -EIO;
1524 +       ea_bdebug(bh, "b_count=%d, refcount=%d",
1525 +               atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
1526 +       end = bh->b_data + bh->b_size;
1527 +       if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
1528 +           HDR(bh)->h_blocks != cpu_to_le32(1)) {
1529 +bad_block:     ext2_error(inode->i_sb, "ext2_xattr_list",
1530 +                       "inode %ld: bad block %d", inode->i_ino, block);
1531 +               error = -EIO;
1532 +               goto cleanup;
1533 +       }
1534 +       /* compute the size required for the list of attribute names */
1535 +       for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
1536 +            entry = EXT2_XATTR_NEXT(entry)) {
1537 +               struct ext2_xattr_handler *handler;
1538 +               struct ext2_xattr_entry *next =
1539 +                       EXT2_XATTR_NEXT(entry);
1540 +               if ((char *)next >= end)
1541 +                       goto bad_block;
1542 +
1543 +               handler = ext2_xattr_handler(entry->e_name_index);
1544 +               if (handler)
1545 +                       size += handler->list(NULL, inode, entry->e_name,
1546 +                                             entry->e_name_len);
1547 +       }
1548 +
1549 +       if (ext2_xattr_cache_insert(bh))
1550 +               ea_idebug(inode, "cache insert failed");
1551 +       if (!buffer) {
1552 +               error = size;
1553 +               goto cleanup;
1554 +       } else {
1555 +               error = -ERANGE;
1556 +               if (size > buffer_size)
1557 +                       goto cleanup;
1558 +       }
1559 +
1560 +       /* list the attribute names */
1561 +       buf = buffer;
1562 +       for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
1563 +            entry = EXT2_XATTR_NEXT(entry)) {
1564 +               struct ext2_xattr_handler *handler;
1565 +               
1566 +               handler = ext2_xattr_handler(entry->e_name_index);
1567 +               if (handler)
1568 +                       buf += handler->list(buf, inode, entry->e_name,
1569 +                                            entry->e_name_len);
1570 +       }
1571 +       error = size;
1572 +
1573 +cleanup:
1574 +       brelse(bh);
1575 +
1576 +       return error;
1577 +}
1578 +
1579 +/*
1580 + * If the EXT2_FEATURE_COMPAT_EXT_ATTR feature of this file system is
1581 + * not set, set it.
1582 + */
1583 +static void ext2_xattr_update_super_block(struct super_block *sb)
1584 +{
1585 +       if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR))
1586 +               return;
1587 +
1588 +       lock_super(sb);
1589 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
1590 +       EXT2_SB(sb)->s_feature_compat |= EXT2_FEATURE_COMPAT_EXT_ATTR;
1591 +#endif
1592 +       EXT2_SB(sb)->s_es->s_feature_compat |=
1593 +               cpu_to_le32(EXT2_FEATURE_COMPAT_EXT_ATTR);
1594 +       sb->s_dirt = 1;
1595 +       mark_buffer_dirty(EXT2_SB(sb)->s_sbh);
1596 +       unlock_super(sb);
1597 +}
1598 +
1599 +/*
1600 + * ext2_xattr_set()
1601 + *
1602 + * Create, replace or remove an extended attribute for this inode. Buffer
1603 + * is NULL to remove an existing extended attribute, and non-NULL to
1604 + * either replace an existing extended attribute, or create a new extended
1605 + * attribute. The flags XATTR_REPLACE and XATTR_CREATE
1606 + * specify that an extended attribute must exist and must not exist
1607 + * previous to the call, respectively.
1608 + *
1609 + * Returns 0, or a negative error number on failure.
1610 + */
1611 +int
1612 +ext2_xattr_set(struct inode *inode, int name_index, const char *name,
1613 +              const void *value, size_t value_len, int flags)
1614 +{
1615 +       struct super_block *sb = inode->i_sb;
1616 +       struct buffer_head *bh = NULL;
1617 +       struct ext2_xattr_header *header = NULL;
1618 +       struct ext2_xattr_entry *here, *last;
1619 +       unsigned int name_len;
1620 +       int block = EXT2_I(inode)->i_file_acl;
1621 +       int min_offs = sb->s_blocksize, not_found = 1, free, error;
1622 +       char *end;
1623 +       
1624 +       /*
1625 +        * header -- Points either into bh, or to a temporarily
1626 +        *           allocated buffer.
1627 +        * here -- The named entry found, or the place for inserting, within
1628 +        *         the block pointed to by header.
1629 +        * last -- Points right after the last named entry within the block
1630 +        *         pointed to by header.
1631 +        * min_offs -- The offset of the first value (values are aligned
1632 +        *             towards the end of the block).
1633 +        * end -- Points right after the block pointed to by header.
1634 +        */
1635 +       
1636 +       ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
1637 +                 name_index, name, value, (long)value_len);
1638 +
1639 +       if (IS_RDONLY(inode))
1640 +               return -EROFS;
1641 +       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
1642 +               return -EPERM;
1643 +       if (value == NULL)
1644 +               value_len = 0;
1645 +       if (name == NULL)
1646 +               return -EINVAL;
1647 +       name_len = strlen(name);
1648 +       if (name_len > 255 || value_len > sb->s_blocksize)
1649 +               return -ERANGE;
1650 +       down(&ext2_xattr_sem);
1651 +
1652 +       if (block) {
1653 +               /* The inode already has an extended attribute block. */
1654 +
1655 +               bh = sb_bread(sb, block);
1656 +               error = -EIO;
1657 +               if (!bh)
1658 +                       goto cleanup;
1659 +               ea_bdebug(bh, "b_count=%d, refcount=%d",
1660 +                       atomic_read(&(bh->b_count)),
1661 +                       le32_to_cpu(HDR(bh)->h_refcount));
1662 +               header = HDR(bh);
1663 +               end = bh->b_data + bh->b_size;
1664 +               if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
1665 +                   header->h_blocks != cpu_to_le32(1)) {
1666 +bad_block:             ext2_error(sb, "ext2_xattr_set",
1667 +                               "inode %ld: bad block %d", inode->i_ino, block);
1668 +                       error = -EIO;
1669 +                       goto cleanup;
1670 +               }
1671 +               /* Find the named attribute. */
1672 +               here = FIRST_ENTRY(bh);
1673 +               while (!IS_LAST_ENTRY(here)) {
1674 +                       struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here);
1675 +                       if ((char *)next >= end)
1676 +                               goto bad_block;
1677 +                       if (!here->e_value_block && here->e_value_size) {
1678 +                               int offs = le16_to_cpu(here->e_value_offs);
1679 +                               if (offs < min_offs)
1680 +                                       min_offs = offs;
1681 +                       }
1682 +                       not_found = name_index - here->e_name_index;
1683 +                       if (!not_found)
1684 +                               not_found = name_len - here->e_name_len;
1685 +                       if (!not_found)
1686 +                               not_found = memcmp(name, here->e_name,name_len);
1687 +                       if (not_found <= 0)
1688 +                               break;
1689 +                       here = next;
1690 +               }
1691 +               last = here;
1692 +               /* We still need to compute min_offs and last. */
1693 +               while (!IS_LAST_ENTRY(last)) {
1694 +                       struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last);
1695 +                       if ((char *)next >= end)
1696 +                               goto bad_block;
1697 +                       if (!last->e_value_block && last->e_value_size) {
1698 +                               int offs = le16_to_cpu(last->e_value_offs);
1699 +                               if (offs < min_offs)
1700 +                                       min_offs = offs;
1701 +                       }
1702 +                       last = next;
1703 +               }
1704 +
1705 +               /* Check whether we have enough space left. */
1706 +               free = min_offs - ((char*)last - (char*)header) - sizeof(__u32);
1707 +       } else {
1708 +               /* We will use a new extended attribute block. */
1709 +               free = sb->s_blocksize -
1710 +                       sizeof(struct ext2_xattr_header) - sizeof(__u32);
1711 +               here = last = NULL;  /* avoid gcc uninitialized warning. */
1712 +       }
1713 +
1714 +       if (not_found) {
1715 +               /* Request to remove a nonexistent attribute? */
1716 +               error = -ENOATTR;
1717 +               if (flags & XATTR_REPLACE)
1718 +                       goto cleanup;
1719 +               error = 0;
1720 +               if (value == NULL)
1721 +                       goto cleanup;
1722 +               else
1723 +                       free -= EXT2_XATTR_LEN(name_len);
1724 +       } else {
1725 +               /* Request to create an existing attribute? */
1726 +               error = -EEXIST;
1727 +               if (flags & XATTR_CREATE)
1728 +                       goto cleanup;
1729 +               if (!here->e_value_block && here->e_value_size) {
1730 +                       unsigned int size = le32_to_cpu(here->e_value_size);
1731 +
1732 +                       if (le16_to_cpu(here->e_value_offs) + size > 
1733 +                           sb->s_blocksize || size > sb->s_blocksize)
1734 +                               goto bad_block;
1735 +                       free += EXT2_XATTR_SIZE(size);
1736 +               }
1737 +       }
1738 +       free -= EXT2_XATTR_SIZE(value_len);
1739 +       error = -ENOSPC;
1740 +       if (free < 0)
1741 +               goto cleanup;
1742 +
1743 +       /* Here we know that we can set the new attribute. */
1744 +
1745 +       if (header) {
1746 +               if (header->h_refcount == cpu_to_le32(1)) {
1747 +                       ea_bdebug(bh, "modifying in-place");
1748 +                       ext2_xattr_cache_remove(bh);
1749 +               } else {
1750 +                       int offset;
1751 +
1752 +                       ea_bdebug(bh, "cloning");
1753 +                       header = kmalloc(bh->b_size, GFP_KERNEL);
1754 +                       error = -ENOMEM;
1755 +                       if (header == NULL)
1756 +                               goto cleanup;
1757 +                       memcpy(header, HDR(bh), bh->b_size);
1758 +                       header->h_refcount = cpu_to_le32(1);
1759 +                       offset = (char *)header - bh->b_data;
1760 +                       here = ENTRY((char *)here + offset);
1761 +                       last = ENTRY((char *)last + offset);
1762 +               }
1763 +       } else {
1764 +               /* Allocate a buffer where we construct the new block. */
1765 +               header = kmalloc(sb->s_blocksize, GFP_KERNEL);
1766 +               error = -ENOMEM;
1767 +               if (header == NULL)
1768 +                       goto cleanup;
1769 +               memset(header, 0, sb->s_blocksize);
1770 +               end = (char *)header + sb->s_blocksize;
1771 +               header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC);
1772 +               header->h_blocks = header->h_refcount = cpu_to_le32(1);
1773 +               last = here = ENTRY(header+1);
1774 +       }
1775 +
1776 +       if (not_found) {
1777 +               /* Insert the new name. */
1778 +               int size = EXT2_XATTR_LEN(name_len);
1779 +               int rest = (char *)last - (char *)here;
1780 +               memmove((char *)here + size, here, rest);
1781 +               memset(here, 0, size);
1782 +               here->e_name_index = name_index;
1783 +               here->e_name_len = name_len;
1784 +               memcpy(here->e_name, name, name_len);
1785 +       } else {
1786 +               /* Remove the old value. */
1787 +               if (!here->e_value_block && here->e_value_size) {
1788 +                       char *first_val = (char *)header + min_offs;
1789 +                       int offs = le16_to_cpu(here->e_value_offs);
1790 +                       char *val = (char *)header + offs;
1791 +                       size_t size = EXT2_XATTR_SIZE(
1792 +                               le32_to_cpu(here->e_value_size));
1793 +                       memmove(first_val + size, first_val, val - first_val);
1794 +                       memset(first_val, 0, size);
1795 +                       here->e_value_offs = 0;
1796 +                       min_offs += size;
1797 +
1798 +                       /* Adjust all value offsets. */
1799 +                       last = ENTRY(header+1);
1800 +                       while (!IS_LAST_ENTRY(last)) {
1801 +                               int o = le16_to_cpu(last->e_value_offs);
1802 +                               if (!last->e_value_block && o < offs)
1803 +                                       last->e_value_offs =
1804 +                                               cpu_to_le16(o + size);
1805 +                               last = EXT2_XATTR_NEXT(last);
1806 +                       }
1807 +               }
1808 +               if (value == NULL) {
1809 +                       /* Remove this attribute. */
1810 +                       if (EXT2_XATTR_NEXT(ENTRY(header+1)) == last) {
1811 +                               /* This block is now empty. */
1812 +                               error = ext2_xattr_set2(inode, bh, NULL);
1813 +                               goto cleanup;
1814 +                       } else {
1815 +                               /* Remove the old name. */
1816 +                               int size = EXT2_XATTR_LEN(name_len);
1817 +                               last = ENTRY((char *)last - size);
1818 +                               memmove(here, (char*)here + size,
1819 +                                       (char*)last - (char*)here);
1820 +                               memset(last, 0, size);
1821 +                       }
1822 +               }
1823 +       }
1824 +
1825 +       if (value != NULL) {
1826 +               /* Insert the new value. */
1827 +               here->e_value_size = cpu_to_le32(value_len);
1828 +               if (value_len) {
1829 +                       size_t size = EXT2_XATTR_SIZE(value_len);
1830 +                       char *val = (char *)header + min_offs - size;
1831 +                       here->e_value_offs =
1832 +                               cpu_to_le16((char *)val - (char *)header);
1833 +                       memset(val + size - EXT2_XATTR_PAD, 0,
1834 +                              EXT2_XATTR_PAD); /* Clear the pad bytes. */
1835 +                       memcpy(val, value, value_len);
1836 +               }
1837 +       }
1838 +       ext2_xattr_rehash(header, here);
1839 +
1840 +       error = ext2_xattr_set2(inode, bh, header);
1841 +
1842 +cleanup:
1843 +       brelse(bh);
1844 +       if (!(bh && header == HDR(bh)))
1845 +               kfree(header);
1846 +       up(&ext2_xattr_sem);
1847 +
1848 +       return error;
1849 +}
1850 +
1851 +/*
1852 + * Second half of ext2_xattr_set(): Update the file system.
1853 + */
1854 +static int
1855 +ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
1856 +               struct ext2_xattr_header *header)
1857 +{
1858 +       struct super_block *sb = inode->i_sb;
1859 +       struct buffer_head *new_bh = NULL;
1860 +       int error;
1861 +
1862 +       if (header) {
1863 +               new_bh = ext2_xattr_cache_find(inode, header);
1864 +               if (new_bh) {
1865 +                       /*
1866 +                        * We found an identical block in the cache.
1867 +                        * The old block will be released after updating
1868 +                        * the inode.
1869 +                        */
1870 +                       ea_bdebug(old_bh, "reusing block %ld",
1871 +                               new_bh->b_blocknr);
1872 +                       
1873 +                       error = -EDQUOT;
1874 +                       if (ext2_xattr_quota_alloc(inode, 1))
1875 +                               goto cleanup;
1876 +                       
1877 +                       HDR(new_bh)->h_refcount = cpu_to_le32(
1878 +                               le32_to_cpu(HDR(new_bh)->h_refcount) + 1);
1879 +                       ea_bdebug(new_bh, "refcount now=%d",
1880 +                               le32_to_cpu(HDR(new_bh)->h_refcount));
1881 +               } else if (old_bh && header == HDR(old_bh)) {
1882 +                       /* Keep this block. */
1883 +                       new_bh = old_bh;
1884 +                       ext2_xattr_cache_insert(new_bh);
1885 +               } else {
1886 +                       /* We need to allocate a new block */
1887 +                       int force = EXT2_I(inode)->i_file_acl != 0;
1888 +                       int block = ext2_xattr_new_block(inode, &error, force);
1889 +                       if (error)
1890 +                               goto cleanup;
1891 +                       ea_idebug(inode, "creating block %d", block);
1892 +
1893 +                       new_bh = sb_getblk(sb, block);
1894 +                       if (!new_bh) {
1895 +                               ext2_xattr_free_block(inode, block);
1896 +                               error = -EIO;
1897 +                               goto cleanup;
1898 +                       }
1899 +                       lock_buffer(new_bh);
1900 +                       memcpy(new_bh->b_data, header, new_bh->b_size);
1901 +                       mark_buffer_uptodate(new_bh, 1);
1902 +                       unlock_buffer(new_bh);
1903 +                       ext2_xattr_cache_insert(new_bh);
1904 +                       
1905 +                       ext2_xattr_update_super_block(sb);
1906 +               }
1907 +               mark_buffer_dirty(new_bh);
1908 +               if (IS_SYNC(inode)) {
1909 +                       ll_rw_block(WRITE, 1, &new_bh);
1910 +                       wait_on_buffer(new_bh); 
1911 +                       error = -EIO;
1912 +                       if (buffer_req(new_bh) && !buffer_uptodate(new_bh))
1913 +                               goto cleanup;
1914 +               }
1915 +       }
1916 +
1917 +       /* Update the inode. */
1918 +       EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
1919 +       inode->i_ctime = CURRENT_TIME;
1920 +       if (IS_SYNC(inode)) {
1921 +               error = ext2_sync_inode (inode);
1922 +               if (error)
1923 +                       goto cleanup;
1924 +       } else
1925 +               mark_inode_dirty(inode);
1926 +
1927 +       error = 0;
1928 +       if (old_bh && old_bh != new_bh) {
1929 +               /*
1930 +                * If there was an old block, and we are not still using it,
1931 +                * we now release the old block.
1932 +               */
1933 +               unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount);
1934 +
1935 +               if (refcount == 1) {
1936 +                       /* Free the old block. */
1937 +                       ea_bdebug(old_bh, "freeing");
1938 +                       ext2_xattr_free_block(inode, old_bh->b_blocknr);
1939 +                       mark_buffer_clean(old_bh);
1940 +               } else {
1941 +                       /* Decrement the refcount only. */
1942 +                       refcount--;
1943 +                       HDR(old_bh)->h_refcount = cpu_to_le32(refcount);
1944 +                       ext2_xattr_quota_free(inode);
1945 +                       mark_buffer_dirty(old_bh);
1946 +                       ea_bdebug(old_bh, "refcount now=%d", refcount);
1947 +               }
1948 +       }
1949 +
1950 +cleanup:
1951 +       if (old_bh != new_bh)
1952 +               brelse(new_bh);
1953 +
1954 +       return error;
1955 +}
1956 +
1957 +/*
1958 + * ext2_xattr_delete_inode()
1959 + *
1960 + * Free extended attribute resources associated with this inode. This
1961 + * is called immediately before an inode is freed.
1962 + */
1963 +void
1964 +ext2_xattr_delete_inode(struct inode *inode)
1965 +{
1966 +       struct buffer_head *bh;
1967 +       unsigned int block = EXT2_I(inode)->i_file_acl;
1968 +
1969 +       if (!block)
1970 +               return;
1971 +       down(&ext2_xattr_sem);
1972 +
1973 +       bh = sb_bread(inode->i_sb, block);
1974 +       if (!bh) {
1975 +               ext2_error(inode->i_sb, "ext2_xattr_delete_inode",
1976 +                       "inode %ld: block %d read error", inode->i_ino, block);
1977 +               goto cleanup;
1978 +       }
1979 +       ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count)));
1980 +       if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
1981 +           HDR(bh)->h_blocks != cpu_to_le32(1)) {
1982 +               ext2_error(inode->i_sb, "ext2_xattr_delete_inode",
1983 +                       "inode %ld: bad block %d", inode->i_ino, block);
1984 +               goto cleanup;
1985 +       }
1986 +       ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
1987 +       if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
1988 +               ext2_xattr_cache_remove(bh);
1989 +               ext2_xattr_free_block(inode, block);
1990 +               bforget(bh);
1991 +               bh = NULL;
1992 +       } else {
1993 +               HDR(bh)->h_refcount = cpu_to_le32(
1994 +                       le32_to_cpu(HDR(bh)->h_refcount) - 1);
1995 +               mark_buffer_dirty(bh);
1996 +               if (IS_SYNC(inode)) {
1997 +                       ll_rw_block(WRITE, 1, &bh);
1998 +                       wait_on_buffer(bh);
1999 +               }
2000 +               ext2_xattr_quota_free(inode);
2001 +       }
2002 +       EXT2_I(inode)->i_file_acl = 0;
2003 +
2004 +cleanup:
2005 +       brelse(bh);
2006 +       up(&ext2_xattr_sem);
2007 +}
2008 +
2009 +/*
2010 + * ext2_xattr_put_super()
2011 + *
2012 + * This is called when a file system is unmounted.
2013 + */
2014 +void
2015 +ext2_xattr_put_super(struct super_block *sb)
2016 +{
2017 +#ifdef CONFIG_EXT2_FS_XATTR_SHARING
2018 +       mb_cache_shrink(ext2_xattr_cache, sb->s_dev);
2019 +#endif
2020 +}
2021 +
2022 +#ifdef CONFIG_EXT2_FS_XATTR_SHARING
2023 +
2024 +/*
2025 + * ext2_xattr_cache_insert()
2026 + *
2027 + * Create a new entry in the extended attribute cache, and insert
2028 + * it unless such an entry is already in the cache.
2029 + *
2030 + * Returns 0, or a negative error number on failure.
2031 + */
2032 +static int
2033 +ext2_xattr_cache_insert(struct buffer_head *bh)
2034 +{
2035 +       __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
2036 +       struct mb_cache_entry *ce;
2037 +       int error;
2038 +
2039 +       ce = mb_cache_entry_alloc(ext2_xattr_cache);
2040 +       if (!ce)
2041 +               return -ENOMEM;
2042 +       error = mb_cache_entry_insert(ce, bh->b_dev, bh->b_blocknr, &hash);
2043 +       if (error) {
2044 +               mb_cache_entry_free(ce);
2045 +               if (error == -EBUSY) {
2046 +                       ea_bdebug(bh, "already in cache (%d cache entries)",
2047 +                               atomic_read(&ext2_xattr_cache->c_entry_count));
2048 +                       error = 0;
2049 +               }
2050 +       } else {
2051 +               ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
2052 +                         atomic_read(&ext2_xattr_cache->c_entry_count));
2053 +               mb_cache_entry_release(ce);
2054 +       }
2055 +       return error;
2056 +}
2057 +
2058 +/*
2059 + * ext2_xattr_cmp()
2060 + *
2061 + * Compare two extended attribute blocks for equality.
2062 + *
2063 + * Returns 0 if the blocks are equal, 1 if they differ, and
2064 + * a negative error number on errors.
2065 + */
2066 +static int
2067 +ext2_xattr_cmp(struct ext2_xattr_header *header1,
2068 +              struct ext2_xattr_header *header2)
2069 +{
2070 +       struct ext2_xattr_entry *entry1, *entry2;
2071 +
2072 +       entry1 = ENTRY(header1+1);
2073 +       entry2 = ENTRY(header2+1);
2074 +       while (!IS_LAST_ENTRY(entry1)) {
2075 +               if (IS_LAST_ENTRY(entry2))
2076 +                       return 1;
2077 +               if (entry1->e_hash != entry2->e_hash ||
2078 +                   entry1->e_name_len != entry2->e_name_len ||
2079 +                   entry1->e_value_size != entry2->e_value_size ||
2080 +                   memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
2081 +                       return 1;
2082 +               if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
2083 +                       return -EIO;
2084 +               if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
2085 +                          (char *)header2 + le16_to_cpu(entry2->e_value_offs),
2086 +                          le32_to_cpu(entry1->e_value_size)))
2087 +                       return 1;
2088 +
2089 +               entry1 = EXT2_XATTR_NEXT(entry1);
2090 +               entry2 = EXT2_XATTR_NEXT(entry2);
2091 +       }
2092 +       if (!IS_LAST_ENTRY(entry2))
2093 +               return 1;
2094 +       return 0;
2095 +}
2096 +
2097 +/*
2098 + * ext2_xattr_cache_find()
2099 + *
2100 + * Find an identical extended attribute block.
2101 + *
2102 + * Returns a pointer to the block found, or NULL if such a block was
2103 + * not found or an error occurred.
2104 + */
2105 +static struct buffer_head *
2106 +ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
2107 +{
2108 +       __u32 hash = le32_to_cpu(header->h_hash);
2109 +       struct mb_cache_entry *ce;
2110 +
2111 +       if (!header->h_hash)
2112 +               return NULL;  /* never share */
2113 +       ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
2114 +       ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, inode->i_dev, hash);
2115 +       while (ce) {
2116 +               struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block);
2117 +
2118 +               if (!bh) {
2119 +                       ext2_error(inode->i_sb, "ext2_xattr_cache_find",
2120 +                               "inode %ld: block %ld read error",
2121 +                               inode->i_ino, ce->e_block);
2122 +               } else if (le32_to_cpu(HDR(bh)->h_refcount) >
2123 +                          EXT2_XATTR_REFCOUNT_MAX) {
2124 +                       ea_idebug(inode, "block %ld refcount %d>%d",ce->e_block,
2125 +                               le32_to_cpu(HDR(bh)->h_refcount),
2126 +                               EXT2_XATTR_REFCOUNT_MAX);
2127 +               } else if (!ext2_xattr_cmp(header, HDR(bh))) {
2128 +                       ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count)));
2129 +                       mb_cache_entry_release(ce);
2130 +                       return bh;
2131 +               }
2132 +               brelse(bh);
2133 +               ce = mb_cache_entry_find_next(ce, 0, inode->i_dev, hash);
2134 +       }
2135 +       return NULL;
2136 +}
2137 +
2138 +/*
2139 + * ext2_xattr_cache_remove()
2140 + *
2141 + * Remove the cache entry of a block from the cache. Called when a
2142 + * block becomes invalid.
2143 + */
2144 +static void
2145 +ext2_xattr_cache_remove(struct buffer_head *bh)
2146 +{
2147 +       struct mb_cache_entry *ce;
2148 +
2149 +       ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_dev, bh->b_blocknr);
2150 +       if (ce) {
2151 +               ea_bdebug(bh, "removing (%d cache entries remaining)",
2152 +                         atomic_read(&ext2_xattr_cache->c_entry_count)-1);
2153 +               mb_cache_entry_free(ce);
2154 +       } else 
2155 +               ea_bdebug(bh, "no cache entry");
2156 +}
2157 +
2158 +#define NAME_HASH_SHIFT 5
2159 +#define VALUE_HASH_SHIFT 16
2160 +
2161 +/*
2162 + * ext2_xattr_hash_entry()
2163 + *
2164 + * Compute the hash of an extended attribute.
2165 + */
2166 +static inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header,
2167 +                                        struct ext2_xattr_entry *entry)
2168 +{
2169 +       __u32 hash = 0;
2170 +       char *name = entry->e_name;
2171 +       int n;
2172 +
2173 +       for (n=0; n < entry->e_name_len; n++) {
2174 +               hash = (hash << NAME_HASH_SHIFT) ^
2175 +                      (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
2176 +                      *name++;
2177 +       }
2178 +
2179 +       if (entry->e_value_block == 0 && entry->e_value_size != 0) {
2180 +               __u32 *value = (__u32 *)((char *)header +
2181 +                       le16_to_cpu(entry->e_value_offs));
2182 +               for (n = (le32_to_cpu(entry->e_value_size) +
2183 +                    EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) {
2184 +                       hash = (hash << VALUE_HASH_SHIFT) ^
2185 +                              (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
2186 +                              le32_to_cpu(*value++);
2187 +               }
2188 +       }
2189 +       entry->e_hash = cpu_to_le32(hash);
2190 +}
2191 +
2192 +#undef NAME_HASH_SHIFT
2193 +#undef VALUE_HASH_SHIFT
2194 +
2195 +#define BLOCK_HASH_SHIFT 16
2196 +
2197 +/*
2198 + * ext2_xattr_rehash()
2199 + *
2200 + * Re-compute the extended attribute hash value after an entry has changed.
2201 + */
2202 +static void ext2_xattr_rehash(struct ext2_xattr_header *header,
2203 +                             struct ext2_xattr_entry *entry)
2204 +{
2205 +       struct ext2_xattr_entry *here;
2206 +       __u32 hash = 0;
2207 +       
2208 +       ext2_xattr_hash_entry(header, entry);
2209 +       here = ENTRY(header+1);
2210 +       while (!IS_LAST_ENTRY(here)) {
2211 +               if (!here->e_hash) {
2212 +                       /* Block is not shared if an entry's hash value == 0 */
2213 +                       hash = 0;
2214 +                       break;
2215 +               }
2216 +               hash = (hash << BLOCK_HASH_SHIFT) ^
2217 +                      (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
2218 +                      le32_to_cpu(here->e_hash);
2219 +               here = EXT2_XATTR_NEXT(here);
2220 +       }
2221 +       header->h_hash = cpu_to_le32(hash);
2222 +}
2223 +
2224 +#undef BLOCK_HASH_SHIFT
2225 +
2226 +int __init
2227 +init_ext2_xattr(void)
2228 +{
2229 +       ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL,
2230 +               sizeof(struct mb_cache_entry) +
2231 +               sizeof(struct mb_cache_entry_index), 1, 61);
2232 +       if (!ext2_xattr_cache)
2233 +               return -ENOMEM;
2234 +
2235 +       return 0;
2236 +}
2237 +
2238 +void
2239 +exit_ext2_xattr(void)
2240 +{
2241 +       mb_cache_destroy(ext2_xattr_cache);
2242 +}
2243 +
2244 +#else  /* CONFIG_EXT2_FS_XATTR_SHARING */
2245 +
2246 +int __init
2247 +init_ext2_xattr(void)
2248 +{
2249 +       return 0;
2250 +}
2251 +
2252 +void
2253 +exit_ext2_xattr(void)
2254 +{
2255 +}
2256 +
2257 +#endif  /* CONFIG_EXT2_FS_XATTR_SHARING */
2258 Index: linux-2.4.19-pre1/fs/ext2/xattr_user.c
2259 ===================================================================
2260 --- linux-2.4.19-pre1.orig/fs/ext2/xattr_user.c 2003-01-30 13:24:37.000000000 +0300
2261 +++ linux-2.4.19-pre1/fs/ext2/xattr_user.c      2004-01-14 01:11:49.000000000 +0300
2262 @@ -0,0 +1,103 @@
2263 +/*
2264 + * linux/fs/ext2/xattr_user.c
2265 + * Handler for extended user attributes.
2266 + *
2267 + * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
2268 + */
2269 +
2270 +#include <linux/module.h>
2271 +#include <linux/string.h>
2272 +#include <linux/fs.h>
2273 +#include <linux/ext2_fs.h>
2274 +#include <linux/ext2_xattr.h>
2275 +
2276 +#ifdef CONFIG_EXT2_FS_POSIX_ACL
2277 +# include <linux/ext2_acl.h>
2278 +#endif
2279 +
2280 +#define XATTR_USER_PREFIX "user."
2281 +
2282 +static size_t
2283 +ext2_xattr_user_list(char *list, struct inode *inode,
2284 +                    const char *name, int name_len)
2285 +{
2286 +       const int prefix_len = sizeof(XATTR_USER_PREFIX)-1;
2287 +
2288 +       if (!test_opt(inode->i_sb, XATTR_USER))
2289 +               return 0;
2290 +
2291 +       if (list) {
2292 +               memcpy(list, XATTR_USER_PREFIX, prefix_len);
2293 +               memcpy(list+prefix_len, name, name_len);
2294 +               list[prefix_len + name_len] = '\0';
2295 +       }
2296 +       return prefix_len + name_len + 1;
2297 +}
2298 +
2299 +static int
2300 +ext2_xattr_user_get(struct inode *inode, const char *name,
2301 +                   void *buffer, size_t size)
2302 +{
2303 +       int error;
2304 +
2305 +       if (strcmp(name, "") == 0)
2306 +               return -EINVAL;
2307 +       if (!test_opt(inode->i_sb, XATTR_USER))
2308 +               return -ENOTSUP;
2309 +#ifdef CONFIG_EXT2_FS_POSIX_ACL
2310 +       error = ext2_permission_locked(inode, MAY_READ);
2311 +#else
2312 +       error = permission(inode, MAY_READ);
2313 +#endif
2314 +       if (error)
2315 +               return error;
2316 +
2317 +       return ext2_xattr_get(inode, EXT2_XATTR_INDEX_USER, name,
2318 +                             buffer, size);
2319 +}
2320 +
2321 +static int
2322 +ext2_xattr_user_set(struct inode *inode, const char *name,
2323 +                   const void *value, size_t size, int flags)
2324 +{
2325 +       int error;
2326 +
2327 +       if (strcmp(name, "") == 0)
2328 +               return -EINVAL;
2329 +       if (!test_opt(inode->i_sb, XATTR_USER))
2330 +               return -ENOTSUP;
2331 +       if ( !S_ISREG(inode->i_mode) &&
2332 +           (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
2333 +               return -EPERM;
2334 +#ifdef CONFIG_EXT2_FS_POSIX_ACL
2335 +       error = ext2_permission_locked(inode, MAY_WRITE);
2336 +#else
2337 +       error = permission(inode, MAY_WRITE);
2338 +#endif
2339 +       if (error)
2340 +               return error;
2341 +
2342 +       return ext2_xattr_set(inode, EXT2_XATTR_INDEX_USER, name,
2343 +                             value, size, flags);
2344 +}
2345 +
2346 +struct ext2_xattr_handler ext2_xattr_user_handler = {
2347 +       prefix: XATTR_USER_PREFIX,
2348 +       list:   ext2_xattr_user_list,
2349 +       get:    ext2_xattr_user_get,
2350 +       set:    ext2_xattr_user_set,
2351 +};
2352 +
2353 +int __init
2354 +init_ext2_xattr_user(void)
2355 +{
2356 +       return ext2_xattr_register(EXT2_XATTR_INDEX_USER,
2357 +                                  &ext2_xattr_user_handler);
2358 +}
2359 +
2360 +void
2361 +exit_ext2_xattr_user(void)
2362 +{
2363 +       ext2_xattr_unregister(EXT2_XATTR_INDEX_USER,
2364 +                             &ext2_xattr_user_handler);
2365 +}
2366 Index: linux-2.4.19-pre1/fs/ext3/Makefile
2367 ===================================================================
2368 --- linux-2.4.19-pre1.orig/fs/ext3/Makefile     2004-01-14 01:11:49.000000000 +0300
2369 +++ linux-2.4.19-pre1/fs/ext3/Makefile  2004-01-14 01:11:49.000000000 +0300
2370 @@ -1,5 +1,5 @@
2371  #
2372 -# Makefile for the linux ext2-filesystem routines.
2373 +# Makefile for the linux ext3-filesystem routines.
2374  #
2375  # Note! Dependencies are done automagically by 'make dep', which also
2376  # removes any old dependencies. DON'T put your own dependencies here
2377 @@ -9,10 +9,14 @@
2378  
2379  O_TARGET := ext3.o
2380  
2381 -export-objs := super.o inode.o
2382 +export-objs := ext3-exports.o
2383  
2384  obj-y    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
2385 -               ioctl.o namei.o super.o symlink.o hash.o
2386 +               ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o
2387  obj-m    := $(O_TARGET)
2388  
2389 +export-objs += xattr.o
2390 +obj-$(CONFIG_EXT3_FS_XATTR) += xattr.o
2391 +obj-$(CONFIG_EXT3_FS_XATTR_USER) += xattr_user.o
2392 +
2393  include $(TOPDIR)/Rules.make
2394 Index: linux-2.4.19-pre1/fs/ext3/file.c
2395 ===================================================================
2396 --- linux-2.4.19-pre1.orig/fs/ext3/file.c       2004-01-14 01:11:49.000000000 +0300
2397 +++ linux-2.4.19-pre1/fs/ext3/file.c    2004-01-14 01:11:49.000000000 +0300
2398 @@ -23,6 +23,7 @@
2399  #include <linux/locks.h>
2400  #include <linux/jbd.h>
2401  #include <linux/ext3_fs.h>
2402 +#include <linux/ext3_xattr.h>
2403  #include <linux/ext3_jbd.h>
2404  #include <linux/smp_lock.h>
2405  
2406 @@ -93,5 +94,9 @@
2407  struct inode_operations ext3_file_inode_operations = {
2408         truncate:       ext3_truncate,          /* BKL held */
2409         setattr:        ext3_setattr,           /* BKL held */
2410 +       setxattr:       ext3_setxattr,          /* BKL held */
2411 +       getxattr:       ext3_getxattr,          /* BKL held */
2412 +       listxattr:      ext3_listxattr,         /* BKL held */
2413 +       removexattr:    ext3_removexattr,       /* BKL held */
2414  };
2415  
2416 Index: linux-2.4.19-pre1/fs/ext3/ialloc.c
2417 ===================================================================
2418 --- linux-2.4.19-pre1.orig/fs/ext3/ialloc.c     2004-01-14 01:10:37.000000000 +0300
2419 +++ linux-2.4.19-pre1/fs/ext3/ialloc.c  2004-01-14 01:11:49.000000000 +0300
2420 @@ -17,6 +17,7 @@
2421  #include <linux/jbd.h>
2422  #include <linux/ext3_fs.h>
2423  #include <linux/ext3_jbd.h>
2424 +#include <linux/ext3_xattr.h>
2425  #include <linux/stat.h>
2426  #include <linux/string.h>
2427  #include <linux/locks.h>
2428 @@ -216,6 +217,7 @@
2429          * as writing the quota to disk may need the lock as well.
2430          */
2431         DQUOT_INIT(inode);
2432 +       ext3_xattr_delete_inode(handle, inode);
2433         DQUOT_FREE_INODE(inode);
2434         DQUOT_DROP(inode);
2435  
2436 Index: linux-2.4.19-pre1/fs/ext3/inode.c
2437 ===================================================================
2438 --- linux-2.4.19-pre1.orig/fs/ext3/inode.c      2004-01-14 01:10:37.000000000 +0300
2439 +++ linux-2.4.19-pre1/fs/ext3/inode.c   2004-01-14 01:11:49.000000000 +0300
2440 @@ -39,6 +39,18 @@
2441   */
2442  #undef SEARCH_FROM_ZERO
2443  
2444 +/*
2445 + * Test whether an inode is a fast symlink.
2446 + */
2447 +static inline int ext3_inode_is_fast_symlink(struct inode *inode)
2448 +{
2449 +       int ea_blocks = inode->u.ext3_i.i_file_acl ?
2450 +               (inode->i_sb->s_blocksize >> 9) : 0;
2451 +
2452 +       return (S_ISLNK(inode->i_mode) &&
2453 +               inode->i_blocks - ea_blocks == 0);
2454 +}
2455 +
2456  /* The ext3 forget function must perform a revoke if we are freeing data
2457   * which has been journaled.  Metadata (eg. indirect blocks) must be
2458   * revoked in all cases. 
2459 @@ -48,7 +60,7 @@
2460   * still needs to be revoked.
2461   */
2462  
2463 -static int ext3_forget(handle_t *handle, int is_metadata,
2464 +int ext3_forget(handle_t *handle, int is_metadata,
2465                        struct inode *inode, struct buffer_head *bh,
2466                        int blocknr)
2467  {
2468 @@ -164,9 +176,7 @@
2469  {
2470         handle_t *handle;
2471         
2472 -       if (is_bad_inode(inode) ||
2473 -           inode->i_ino == EXT3_ACL_IDX_INO ||
2474 -           inode->i_ino == EXT3_ACL_DATA_INO)
2475 +       if (is_bad_inode(inode))
2476                 goto no_delete;
2477  
2478         lock_kernel();
2479 @@ -1845,6 +1855,8 @@
2480         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
2481             S_ISLNK(inode->i_mode)))
2482                 return;
2483 +       if (ext3_inode_is_fast_symlink(inode))
2484 +               return;
2485         if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
2486                 return;
2487  
2488 @@ -1992,8 +2004,6 @@
2489         struct ext3_group_desc * gdp;
2490                 
2491         if ((inode->i_ino != EXT3_ROOT_INO &&
2492 -               inode->i_ino != EXT3_ACL_IDX_INO &&
2493 -               inode->i_ino != EXT3_ACL_DATA_INO &&
2494                 inode->i_ino != EXT3_JOURNAL_INO &&
2495                 inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) ||
2496                 inode->i_ino > le32_to_cpu(
2497 @@ -2120,10 +2130,7 @@
2498  
2499         brelse (iloc.bh);
2500  
2501 -       if (inode->i_ino == EXT3_ACL_IDX_INO ||
2502 -           inode->i_ino == EXT3_ACL_DATA_INO)
2503 -               /* Nothing to do */ ;
2504 -       else if (S_ISREG(inode->i_mode)) {
2505 +       if (S_ISREG(inode->i_mode)) {
2506                 inode->i_op = &ext3_file_inode_operations;
2507                 inode->i_fop = &ext3_file_operations;
2508                 inode->i_mapping->a_ops = &ext3_aops;
2509 @@ -2131,15 +2138,17 @@
2510                 inode->i_op = &ext3_dir_inode_operations;
2511                 inode->i_fop = &ext3_dir_operations;
2512         } else if (S_ISLNK(inode->i_mode)) {
2513 -               if (!inode->i_blocks)
2514 +               if (ext3_inode_is_fast_symlink(inode))
2515                         inode->i_op = &ext3_fast_symlink_inode_operations;
2516                 else {
2517 -                       inode->i_op = &page_symlink_inode_operations;
2518 +                       inode->i_op = &ext3_symlink_inode_operations;
2519                         inode->i_mapping->a_ops = &ext3_aops;
2520                 }
2521 -       } else 
2522 +       } else {
2523 +               inode->i_op = &ext3_special_inode_operations;
2524                 init_special_inode(inode, inode->i_mode,
2525                                    le32_to_cpu(iloc.raw_inode->i_block[0]));
2526 +       }
2527         /* inode->i_attr_flags = 0;                             unused */
2528         if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) {
2529                 /* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */
2530 Index: linux-2.4.19-pre1/fs/ext3/namei.c
2531 ===================================================================
2532 --- linux-2.4.19-pre1.orig/fs/ext3/namei.c      2004-01-14 01:11:49.000000000 +0300
2533 +++ linux-2.4.19-pre1/fs/ext3/namei.c   2004-01-14 01:11:49.000000000 +0300
2534 @@ -29,6 +29,7 @@
2535  #include <linux/sched.h>
2536  #include <linux/ext3_fs.h>
2537  #include <linux/ext3_jbd.h>
2538 +#include <linux/ext3_xattr.h>
2539  #include <linux/fcntl.h>
2540  #include <linux/stat.h>
2541  #include <linux/string.h>
2542 @@ -1612,7 +1613,7 @@
2543         if (IS_SYNC(dir))
2544                 handle->h_sync = 1;
2545  
2546 -       inode = ext3_new_inode (handle, dir, S_IFDIR);
2547 +       inode = ext3_new_inode (handle, dir, S_IFDIR | mode);
2548         err = PTR_ERR(inode);
2549         if (IS_ERR(inode))
2550                 goto out_stop;
2551 @@ -1620,7 +1621,6 @@
2552         inode->i_op = &ext3_dir_inode_operations;
2553         inode->i_fop = &ext3_dir_operations;
2554         inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
2555 -       inode->i_blocks = 0;    
2556         dir_block = ext3_bread (handle, inode, 0, 1, &err);
2557         if (!dir_block) {
2558                 inode->i_nlink--; /* is this nlink == 0? */
2559 @@ -1647,9 +1647,6 @@
2560         BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata");
2561         ext3_journal_dirty_metadata(handle, dir_block);
2562         brelse (dir_block);
2563 -       inode->i_mode = S_IFDIR | mode;
2564 -       if (dir->i_mode & S_ISGID)
2565 -               inode->i_mode |= S_ISGID;
2566         ext3_mark_inode_dirty(handle, inode);
2567         err = ext3_add_entry (handle, dentry, inode);
2568         if (err) {
2569 @@ -2018,7 +2015,7 @@
2570                 goto out_stop;
2571  
2572         if (l > sizeof (EXT3_I(inode)->i_data)) {
2573 -               inode->i_op = &page_symlink_inode_operations;
2574 +               inode->i_op = &ext3_symlink_inode_operations;
2575                 inode->i_mapping->a_ops = &ext3_aops;
2576                 /*
2577                  * block_symlink() calls back into ext3_prepare/commit_write.
2578 @@ -2245,4 +2242,16 @@
2579         rmdir:          ext3_rmdir,             /* BKL held */
2580         mknod:          ext3_mknod,             /* BKL held */
2581         rename:         ext3_rename,            /* BKL held */
2582 +       setxattr:       ext3_setxattr,          /* BKL held */
2583 +       getxattr:       ext3_getxattr,          /* BKL held */
2584 +       listxattr:      ext3_listxattr,         /* BKL held */
2585 +       removexattr:    ext3_removexattr,       /* BKL held */
2586  };
2587 +
2588 +struct inode_operations ext3_special_inode_operations = {
2589 +       setxattr:       ext3_setxattr,          /* BKL held */
2590 +       getxattr:       ext3_getxattr,          /* BKL held */
2591 +       listxattr:      ext3_listxattr,         /* BKL held */
2592 +       removexattr:    ext3_removexattr,       /* BKL held */
2593 +};
2594 +
2595 Index: linux-2.4.19-pre1/fs/ext3/super.c
2596 ===================================================================
2597 --- linux-2.4.19-pre1.orig/fs/ext3/super.c      2004-01-14 01:11:49.000000000 +0300
2598 +++ linux-2.4.19-pre1/fs/ext3/super.c   2004-01-14 01:11:49.000000000 +0300
2599 @@ -24,6 +24,7 @@
2600  #include <linux/jbd.h>
2601  #include <linux/ext3_fs.h>
2602  #include <linux/ext3_jbd.h>
2603 +#include <linux/ext3_xattr.h>
2604  #include <linux/slab.h>
2605  #include <linux/init.h>
2606  #include <linux/locks.h>
2607 @@ -404,6 +405,7 @@
2608         kdev_t j_dev = sbi->s_journal->j_dev;
2609         int i;
2610  
2611 +       ext3_xattr_put_super(sb);
2612         journal_destroy(sbi->s_journal);
2613         if (!(sb->s_flags & MS_RDONLY)) {
2614                 EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
2615 @@ -499,6 +501,7 @@
2616                           int is_remount)
2617  {
2618         unsigned long *mount_options = &sbi->s_mount_opt;
2619 +       
2620         uid_t *resuid = &sbi->s_resuid;
2621         gid_t *resgid = &sbi->s_resgid;
2622         char * this_char;
2623 @@ -511,6 +514,13 @@
2624              this_char = strtok (NULL, ",")) {
2625                 if ((value = strchr (this_char, '=')) != NULL)
2626                         *value++ = 0;
2627 +#ifdef CONFIG_EXT3_FS_XATTR_USER
2628 +               if (!strcmp (this_char, "user_xattr"))
2629 +                       set_opt (*mount_options, XATTR_USER);
2630 +               else if (!strcmp (this_char, "nouser_xattr"))
2631 +                       clear_opt (*mount_options, XATTR_USER);
2632 +               else
2633 +#endif
2634                 if (!strcmp (this_char, "bsddf"))
2635                         clear_opt (*mount_options, MINIX_DF);
2636                 else if (!strcmp (this_char, "nouid32")) {
2637 @@ -924,6 +934,12 @@
2638         sbi->s_mount_opt = 0;
2639         sbi->s_resuid = EXT3_DEF_RESUID;
2640         sbi->s_resgid = EXT3_DEF_RESGID;
2641 +
2642 +       /* Default extended attribute flags */
2643 +#ifdef CONFIG_EXT3_FS_XATTR_USER
2644 +       /* set_opt(sbi->s_mount_opt, XATTR_USER); */
2645 +#endif
2646 +
2647         if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) {
2648                 sb->s_dev = 0;
2649                 goto out_fail;
2650 @@ -1742,17 +1758,29 @@
2651  
2652  static int __init init_ext3_fs(void)
2653  {
2654 -        return register_filesystem(&ext3_fs_type);
2655 +       int error = init_ext3_xattr();
2656 +       if (error)
2657 +               return error;
2658 +       error = init_ext3_xattr_user();
2659 +       if (error)
2660 +               goto fail;
2661 +       error = register_filesystem(&ext3_fs_type);
2662 +       if (!error)
2663 +               return 0;
2664 +       
2665 +       exit_ext3_xattr_user();
2666 +fail:
2667 +       exit_ext3_xattr();
2668 +       return error;
2669  }
2670  
2671  static void __exit exit_ext3_fs(void)
2672  {
2673         unregister_filesystem(&ext3_fs_type);
2674 +       exit_ext3_xattr_user();
2675 +       exit_ext3_xattr();
2676  }
2677  
2678 -EXPORT_SYMBOL(ext3_force_commit);
2679 -EXPORT_SYMBOL(ext3_bread);
2680 -
2681  MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
2682  MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions");
2683  MODULE_LICENSE("GPL");
2684 Index: linux-2.4.19-pre1/fs/ext3/symlink.c
2685 ===================================================================
2686 --- linux-2.4.19-pre1.orig/fs/ext3/symlink.c    2001-11-10 01:25:04.000000000 +0300
2687 +++ linux-2.4.19-pre1/fs/ext3/symlink.c 2004-01-14 01:11:49.000000000 +0300
2688 @@ -20,6 +20,7 @@
2689  #include <linux/fs.h>
2690  #include <linux/jbd.h>
2691  #include <linux/ext3_fs.h>
2692 +#include <linux/ext3_xattr.h>
2693  
2694  static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen)
2695  {
2696 @@ -33,7 +34,20 @@
2697         return vfs_follow_link(nd, s);
2698  }
2699  
2700 +struct inode_operations ext3_symlink_inode_operations = {
2701 +       readlink:       page_readlink,          /* BKL not held.  Don't need */
2702 +       follow_link:    page_follow_link,       /* BKL not held.  Don't need */
2703 +       setxattr:       ext3_setxattr,          /* BKL held */
2704 +       getxattr:       ext3_getxattr,          /* BKL held */
2705 +       listxattr:      ext3_listxattr,         /* BKL held */
2706 +       removexattr:    ext3_removexattr,       /* BKL held */
2707 +};
2708 +
2709  struct inode_operations ext3_fast_symlink_inode_operations = {
2710         readlink:       ext3_readlink,          /* BKL not held.  Don't need */
2711         follow_link:    ext3_follow_link,       /* BKL not held.  Don't need */
2712 +       setxattr:       ext3_setxattr,          /* BKL held */
2713 +       getxattr:       ext3_getxattr,          /* BKL held */
2714 +       listxattr:      ext3_listxattr,         /* BKL held */
2715 +       removexattr:    ext3_removexattr,       /* BKL held */
2716  };
2717 Index: linux-2.4.19-pre1/fs/ext3/xattr.c
2718 ===================================================================
2719 --- linux-2.4.19-pre1.orig/fs/ext3/xattr.c      2003-01-30 13:24:37.000000000 +0300
2720 +++ linux-2.4.19-pre1/fs/ext3/xattr.c   2004-01-14 01:11:49.000000000 +0300
2721 @@ -0,0 +1,1225 @@
2722 +/*
2723 + * linux/fs/ext3/xattr.c
2724 + *
2725 + * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
2726 + *
2727 + * Fix by Harrison Xing <harrison@mountainviewdata.com>.
2728 + * Ext3 code with a lot of help from Eric Jarman <ejarman@acm.org>.
2729 + * Extended attributes for symlinks and special files added per
2730 + *  suggestion of Luka Renko <luka.renko@hermes.si>.
2731 + */
2732 +
2733 +/*
2734 + * Extended attributes are stored on disk blocks allocated outside of
2735 + * any inode. The i_file_acl field is then made to point to this allocated
2736 + * block. If all extended attributes of an inode are identical, these
2737 + * inodes may share the same extended attribute block. Such situations
2738 + * are automatically detected by keeping a cache of recent attribute block
2739 + * numbers and hashes over the block's contents in memory.
2740 + *
2741 + *
2742 + * Extended attribute block layout:
2743 + *
2744 + *   +------------------+
2745 + *   | header           |
2746 + *   | entry 1          | |
2747 + *   | entry 2          | | growing downwards
2748 + *   | entry 3          | v
2749 + *   | four null bytes  |
2750 + *   | . . .            |
2751 + *   | value 1          | ^
2752 + *   | value 3          | | growing upwards
2753 + *   | value 2          | |
2754 + *   +------------------+
2755 + *
2756 + * The block header is followed by multiple entry descriptors. These entry
2757 + * descriptors are variable in size, and alligned to EXT3_XATTR_PAD
2758 + * byte boundaries. The entry descriptors are sorted by attribute name,
2759 + * so that two extended attribute blocks can be compared efficiently.
2760 + *
2761 + * Attribute values are aligned to the end of the block, stored in
2762 + * no specific order. They are also padded to EXT3_XATTR_PAD byte
2763 + * boundaries. No additional gaps are left between them.
2764 + *
2765 + * Locking strategy
2766 + * ----------------
2767 + * The VFS already holds the BKL and the inode->i_sem semaphore when any of
2768 + * the xattr inode operations are called, so we are guaranteed that only one
2769 + * processes accesses extended attributes of an inode at any time.
2770 + *
2771 + * For writing we also grab the ext3_xattr_sem semaphore. This ensures that
2772 + * only a single process is modifying an extended attribute block, even
2773 + * if the block is shared among inodes.
2774 + *
2775 + * Note for porting to 2.5
2776 + * -----------------------
2777 + * The BKL will no longer be held in the xattr inode operations.
2778 + */
2779 +
2780 +#include <linux/module.h>
2781 +#include <linux/fs.h>
2782 +#include <linux/locks.h>
2783 +#include <linux/slab.h>
2784 +#include <linux/ext3_jbd.h>
2785 +#include <linux/ext3_fs.h>
2786 +#include <linux/ext3_xattr.h>
2787 +#include <linux/mbcache.h>
2788 +#include <linux/quotaops.h>
2789 +#include <asm/semaphore.h>
2790 +#include <linux/compatmac.h>
2791 +
2792 +#define EXT3_EA_USER "user."
2793 +
2794 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
2795 +# define mark_buffer_dirty(bh) mark_buffer_dirty(bh, 1)
2796 +#endif
2797 +
2798 +#define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data))
2799 +#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr))
2800 +#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
2801 +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
2802 +
2803 +#ifdef EXT3_XATTR_DEBUG
2804 +# define ea_idebug(inode, f...) do { \
2805 +               printk(KERN_DEBUG "inode %s:%ld: ", \
2806 +                       kdevname(inode->i_dev), inode->i_ino); \
2807 +               printk(f); \
2808 +               printk("\n"); \
2809 +       } while (0)
2810 +# define ea_bdebug(bh, f...) do { \
2811 +               printk(KERN_DEBUG "block %s:%ld: ", \
2812 +                       kdevname(bh->b_dev), bh->b_blocknr); \
2813 +               printk(f); \
2814 +               printk("\n"); \
2815 +       } while (0)
2816 +#else
2817 +# define ea_idebug(f...)
2818 +# define ea_bdebug(f...)
2819 +#endif
2820 +
2821 +static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
2822 +                          struct ext3_xattr_header *);
2823 +
2824 +#ifdef CONFIG_EXT3_FS_XATTR_SHARING
2825 +
2826 +static int ext3_xattr_cache_insert(struct buffer_head *);
2827 +static struct buffer_head *ext3_xattr_cache_find(struct inode *,
2828 +                                                struct ext3_xattr_header *);
2829 +static void ext3_xattr_cache_remove(struct buffer_head *);
2830 +static void ext3_xattr_rehash(struct ext3_xattr_header *,
2831 +                             struct ext3_xattr_entry *);
2832 +
2833 +static struct mb_cache *ext3_xattr_cache;
2834 +
2835 +#else
2836 +# define ext3_xattr_cache_insert(bh) 0
2837 +# define ext3_xattr_cache_find(inode, header) NULL
2838 +# define ext3_xattr_cache_remove(bh) while(0) {}
2839 +# define ext3_xattr_rehash(header, entry) while(0) {}
2840 +#endif
2841 +
2842 +/*
2843 + * If a file system does not share extended attributes among inodes,
2844 + * we should not need the ext3_xattr_sem semaphore. However, the
2845 + * filesystem may still contain shared blocks, so we always take
2846 + * the lock.
2847 + */
2848 +
2849 +DECLARE_MUTEX(ext3_xattr_sem);
2850 +
2851 +static inline int
2852 +ext3_xattr_new_block(handle_t *handle, struct inode *inode,
2853 +                    int * errp, int force)
2854 +{
2855 +       struct super_block *sb = inode->i_sb;
2856 +       int goal = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
2857 +               EXT3_I(inode)->i_block_group * EXT3_BLOCKS_PER_GROUP(sb);
2858 +
2859 +       /* How can we enforce the allocation? */
2860 +       int block = ext3_new_block(handle, inode, goal, 0, 0, errp);
2861 +#ifdef OLD_QUOTAS
2862 +       if (!*errp)
2863 +               inode->i_blocks += inode->i_sb->s_blocksize >> 9;
2864 +#endif
2865 +       return block;
2866 +}
2867 +
2868 +static inline int
2869 +ext3_xattr_quota_alloc(struct inode *inode, int force)
2870 +{
2871 +       /* How can we enforce the allocation? */
2872 +#ifdef OLD_QUOTAS
2873 +       int error = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1);
2874 +       if (!error)
2875 +               inode->i_blocks += inode->i_sb->s_blocksize >> 9;
2876 +#else
2877 +       int error = DQUOT_ALLOC_BLOCK(inode, 1);
2878 +#endif
2879 +       return error;
2880 +}
2881 +
2882 +#ifdef OLD_QUOTAS
2883 +
2884 +static inline void
2885 +ext3_xattr_quota_free(struct inode *inode)
2886 +{
2887 +       DQUOT_FREE_BLOCK(inode->i_sb, inode, 1);
2888 +       inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
2889 +}
2890 +
2891 +static inline void
2892 +ext3_xattr_free_block(handle_t *handle, struct inode * inode,
2893 +                     unsigned long block)
2894 +{
2895 +       ext3_free_blocks(handle, inode, block, 1);
2896 +       inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
2897 +}
2898 +
2899 +#else
2900 +# define ext3_xattr_quota_free(inode) \
2901 +       DQUOT_FREE_BLOCK(inode, 1)
2902 +# define ext3_xattr_free_block(handle, inode, block) \
2903 +       ext3_free_blocks(handle, inode, block, 1)
2904 +#endif
2905 +
2906 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
2907 +
2908 +static inline struct buffer_head *
2909 +sb_bread(struct super_block *sb, int block)
2910 +{
2911 +       return bread(sb->s_dev, block, sb->s_blocksize);
2912 +}
2913 +
2914 +static inline struct buffer_head *
2915 +sb_getblk(struct super_block *sb, int block)
2916 +{
2917 +       return getblk(sb->s_dev, block, sb->s_blocksize);
2918 +}
2919 +
2920 +#endif
2921 +
2922 +struct ext3_xattr_handler *ext3_xattr_handlers[EXT3_XATTR_INDEX_MAX];
2923 +rwlock_t ext3_handler_lock = RW_LOCK_UNLOCKED;
2924 +
2925 +int
2926 +ext3_xattr_register(int name_index, struct ext3_xattr_handler *handler)
2927 +{
2928 +       int error = -EINVAL;
2929 +
2930 +       if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) {
2931 +               write_lock(&ext3_handler_lock);
2932 +               if (!ext3_xattr_handlers[name_index-1]) {
2933 +                       ext3_xattr_handlers[name_index-1] = handler;
2934 +                       error = 0;
2935 +               }
2936 +               write_unlock(&ext3_handler_lock);
2937 +       }
2938 +       return error;
2939 +}
2940 +
2941 +void
2942 +ext3_xattr_unregister(int name_index, struct ext3_xattr_handler *handler)
2943 +{
2944 +       if (name_index > 0 || name_index <= EXT3_XATTR_INDEX_MAX) {
2945 +               write_lock(&ext3_handler_lock);
2946 +               ext3_xattr_handlers[name_index-1] = NULL;
2947 +               write_unlock(&ext3_handler_lock);
2948 +       }
2949 +}
2950 +
2951 +static inline const char *
2952 +strcmp_prefix(const char *a, const char *a_prefix)
2953 +{
2954 +       while (*a_prefix && *a == *a_prefix) {
2955 +               a++;
2956 +               a_prefix++;
2957 +       }
2958 +       return *a_prefix ? NULL : a;
2959 +}
2960 +
2961 +/*
2962 + * Decode the extended attribute name, and translate it into
2963 + * the name_index and name suffix.
2964 + */
2965 +static inline struct ext3_xattr_handler *
2966 +ext3_xattr_resolve_name(const char **name)
2967 +{
2968 +       struct ext3_xattr_handler *handler = NULL;
2969 +       int i;
2970 +
2971 +       if (!*name)
2972 +               return NULL;
2973 +       read_lock(&ext3_handler_lock);
2974 +       for (i=0; i<EXT3_XATTR_INDEX_MAX; i++) {
2975 +               if (ext3_xattr_handlers[i]) {
2976 +                       const char *n = strcmp_prefix(*name,
2977 +                               ext3_xattr_handlers[i]->prefix);
2978 +                       if (n) {
2979 +                               handler = ext3_xattr_handlers[i];
2980 +                               *name = n;
2981 +                               break;
2982 +                       }
2983 +               }
2984 +       }
2985 +       read_unlock(&ext3_handler_lock);
2986 +       return handler;
2987 +}
2988 +
2989 +static inline struct ext3_xattr_handler *
2990 +ext3_xattr_handler(int name_index)
2991 +{
2992 +       struct ext3_xattr_handler *handler = NULL;
2993 +       if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) {
2994 +               read_lock(&ext3_handler_lock);
2995 +               handler = ext3_xattr_handlers[name_index-1];
2996 +               read_unlock(&ext3_handler_lock);
2997 +       }
2998 +       return handler;
2999 +}
3000 +
3001 +/*
3002 + * Inode operation getxattr()
3003 + *
3004 + * dentry->d_inode->i_sem down
3005 + * BKL held [before 2.5.x]
3006 + */
3007 +ssize_t
3008 +ext3_getxattr(struct dentry *dentry, const char *name,
3009 +             void *buffer, size_t size)
3010 +{
3011 +       struct ext3_xattr_handler *handler;
3012 +       struct inode *inode = dentry->d_inode;
3013 +
3014 +       handler = ext3_xattr_resolve_name(&name);
3015 +       if (!handler)
3016 +               return -ENOTSUP;
3017 +       return handler->get(inode, name, buffer, size);
3018 +}
3019 +
3020 +/*
3021 + * Inode operation listxattr()
3022 + *
3023 + * dentry->d_inode->i_sem down
3024 + * BKL held [before 2.5.x]
3025 + */
3026 +ssize_t
3027 +ext3_listxattr(struct dentry *dentry, char *buffer, size_t size)
3028 +{
3029 +       return ext3_xattr_list(dentry->d_inode, buffer, size);
3030 +}
3031 +
3032 +/*
3033 + * Inode operation setxattr()
3034 + *
3035 + * dentry->d_inode->i_sem down
3036 + * BKL held [before 2.5.x]
3037 + */
3038 +int
3039 +ext3_setxattr(struct dentry *dentry, const char *name,
3040 +             const void *value, size_t size, int flags)
3041 +{
3042 +       struct ext3_xattr_handler *handler;
3043 +       struct inode *inode = dentry->d_inode;
3044 +
3045 +       if (size == 0)
3046 +               value = "";  /* empty EA, do not remove */
3047 +       handler = ext3_xattr_resolve_name(&name);
3048 +       if (!handler)
3049 +               return -ENOTSUP;
3050 +       return handler->set(inode, name, value, size, flags);
3051 +}
3052 +
3053 +/*
3054 + * Inode operation removexattr()
3055 + *
3056 + * dentry->d_inode->i_sem down
3057 + * BKL held [before 2.5.x]
3058 + */
3059 +int
3060 +ext3_removexattr(struct dentry *dentry, const char *name)
3061 +{
3062 +       struct ext3_xattr_handler *handler;
3063 +       struct inode *inode = dentry->d_inode;
3064 +
3065 +       handler = ext3_xattr_resolve_name(&name);
3066 +       if (!handler)
3067 +               return -ENOTSUP;
3068 +       return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
3069 +}
3070 +
3071 +/*
3072 + * ext3_xattr_get()
3073 + *
3074 + * Copy an extended attribute into the buffer
3075 + * provided, or compute the buffer size required.
3076 + * Buffer is NULL to compute the size of the buffer required.
3077 + *
3078 + * Returns a negative error number on failure, or the number of bytes
3079 + * used / required on success.
3080 + */
3081 +int
3082 +ext3_xattr_get(struct inode *inode, int name_index, const char *name,
3083 +              void *buffer, size_t buffer_size)
3084 +{
3085 +       struct buffer_head *bh = NULL;
3086 +       struct ext3_xattr_entry *entry;
3087 +       unsigned int block, size;
3088 +       char *end;
3089 +       int name_len, error;
3090 +
3091 +       ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
3092 +                 name_index, name, buffer, (long)buffer_size);
3093 +
3094 +       if (name == NULL)
3095 +               return -EINVAL;
3096 +       if (!EXT3_I(inode)->i_file_acl)
3097 +               return -ENOATTR;
3098 +       block = EXT3_I(inode)->i_file_acl;
3099 +       ea_idebug(inode, "reading block %d", block);
3100 +       bh = sb_bread(inode->i_sb, block);
3101 +       if (!bh)
3102 +               return -EIO;
3103 +       ea_bdebug(bh, "b_count=%d, refcount=%d",
3104 +               atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
3105 +       end = bh->b_data + bh->b_size;
3106 +       if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
3107 +           HDR(bh)->h_blocks != cpu_to_le32(1)) {
3108 +bad_block:     ext3_error(inode->i_sb, "ext3_xattr_get",
3109 +                       "inode %ld: bad block %d", inode->i_ino, block);
3110 +               error = -EIO;
3111 +               goto cleanup;
3112 +       }
3113 +       /* find named attribute */
3114 +       name_len = strlen(name);
3115 +
3116 +       error = -ERANGE;
3117 +       if (name_len > 255)
3118 +               goto cleanup;
3119 +       entry = FIRST_ENTRY(bh);
3120 +       while (!IS_LAST_ENTRY(entry)) {
3121 +               struct ext3_xattr_entry *next =
3122 +                       EXT3_XATTR_NEXT(entry);
3123 +               if ((char *)next >= end)
3124 +                       goto bad_block;
3125 +               if (name_index == entry->e_name_index &&
3126 +                   name_len == entry->e_name_len &&
3127 +                   memcmp(name, entry->e_name, name_len) == 0)
3128 +                       goto found;
3129 +               entry = next;
3130 +       }
3131 +       /* Check the remaining name entries */
3132 +       while (!IS_LAST_ENTRY(entry)) {
3133 +               struct ext3_xattr_entry *next =
3134 +                       EXT3_XATTR_NEXT(entry);
3135 +               if ((char *)next >= end)
3136 +                       goto bad_block;
3137 +               entry = next;
3138 +       }
3139 +       if (ext3_xattr_cache_insert(bh))
3140 +               ea_idebug(inode, "cache insert failed");
3141 +       error = -ENOATTR;
3142 +       goto cleanup;
3143 +found:
3144 +       /* check the buffer size */
3145 +       if (entry->e_value_block != 0)
3146 +               goto bad_block;
3147 +       size = le32_to_cpu(entry->e_value_size);
3148 +       if (size > inode->i_sb->s_blocksize ||
3149 +           le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
3150 +               goto bad_block;
3151 +
3152 +       if (ext3_xattr_cache_insert(bh))
3153 +               ea_idebug(inode, "cache insert failed");
3154 +       if (buffer) {
3155 +               error = -ERANGE;
3156 +               if (size > buffer_size)
3157 +                       goto cleanup;
3158 +               /* return value of attribute */
3159 +               memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
3160 +                       size);
3161 +       }
3162 +       error = size;
3163 +
3164 +cleanup:
3165 +       brelse(bh);
3166 +
3167 +       return error;
3168 +}
3169 +
3170 +/*
3171 + * ext3_xattr_list()
3172 + *
3173 + * Copy a list of attribute names into the buffer
3174 + * provided, or compute the buffer size required.
3175 + * Buffer is NULL to compute the size of the buffer required.
3176 + *
3177 + * Returns a negative error number on failure, or the number of bytes
3178 + * used / required on success.
3179 + */
3180 +int
3181 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
3182 +{
3183 +       struct buffer_head *bh = NULL;
3184 +       struct ext3_xattr_entry *entry;
3185 +       unsigned int block, size = 0;
3186 +       char *buf, *end;
3187 +       int error;
3188 +
3189 +       ea_idebug(inode, "buffer=%p, buffer_size=%ld",
3190 +                 buffer, (long)buffer_size);
3191 +
3192 +       if (!EXT3_I(inode)->i_file_acl)
3193 +               return 0;
3194 +       block = EXT3_I(inode)->i_file_acl;
3195 +       ea_idebug(inode, "reading block %d", block);
3196 +       bh = sb_bread(inode->i_sb, block);
3197 +       if (!bh)
3198 +               return -EIO;
3199 +       ea_bdebug(bh, "b_count=%d, refcount=%d",
3200 +               atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
3201 +       end = bh->b_data + bh->b_size;
3202 +       if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
3203 +           HDR(bh)->h_blocks != cpu_to_le32(1)) {
3204 +bad_block:     ext3_error(inode->i_sb, "ext3_xattr_list",
3205 +                       "inode %ld: bad block %d", inode->i_ino, block);
3206 +               error = -EIO;
3207 +               goto cleanup;
3208 +       }
3209 +       /* compute the size required for the list of attribute names */
3210 +       for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
3211 +            entry = EXT3_XATTR_NEXT(entry)) {
3212 +               struct ext3_xattr_handler *handler;
3213 +               struct ext3_xattr_entry *next =
3214 +                       EXT3_XATTR_NEXT(entry);
3215 +               if ((char *)next >= end)
3216 +                       goto bad_block;
3217 +
3218 +               handler = ext3_xattr_handler(entry->e_name_index);
3219 +               if (handler)
3220 +                       size += handler->list(NULL, inode, entry->e_name,
3221 +                                             entry->e_name_len);
3222 +       }
3223 +
3224 +       if (ext3_xattr_cache_insert(bh))
3225 +               ea_idebug(inode, "cache insert failed");
3226 +       if (!buffer) {
3227 +               error = size;
3228 +               goto cleanup;
3229 +       } else {
3230 +               error = -ERANGE;
3231 +               if (size > buffer_size)
3232 +                       goto cleanup;
3233 +       }
3234 +
3235 +       /* list the attribute names */
3236 +       buf = buffer;
3237 +       for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
3238 +            entry = EXT3_XATTR_NEXT(entry)) {
3239 +               struct ext3_xattr_handler *handler;
3240 +
3241 +               handler = ext3_xattr_handler(entry->e_name_index);
3242 +               if (handler)
3243 +                       buf += handler->list(buf, inode, entry->e_name,
3244 +                                            entry->e_name_len);
3245 +       }
3246 +       error = size;
3247 +
3248 +cleanup:
3249 +       brelse(bh);
3250 +
3251 +       return error;
3252 +}
3253 +
3254 +/*
3255 + * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
3256 + * not set, set it.
3257 + */
3258 +static void ext3_xattr_update_super_block(handle_t *handle,
3259 +                                         struct super_block *sb)
3260 +{
3261 +       if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR))
3262 +               return;
3263 +
3264 +       lock_super(sb);
3265 +       ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh);
3266 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
3267 +       EXT3_SB(sb)->s_feature_compat |= EXT3_FEATURE_COMPAT_EXT_ATTR;
3268 +#endif
3269 +       EXT3_SB(sb)->s_es->s_feature_compat |=
3270 +               cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR);
3271 +       sb->s_dirt = 1;
3272 +       ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
3273 +       unlock_super(sb);
3274 +}
3275 +
3276 +/*
3277 + * ext3_xattr_set()
3278 + *
3279 + * Create, replace or remove an extended attribute for this inode. Buffer
3280 + * is NULL to remove an existing extended attribute, and non-NULL to
3281 + * either replace an existing extended attribute, or create a new extended
3282 + * attribute. The flags XATTR_REPLACE and XATTR_CREATE
3283 + * specify that an extended attribute must exist and must not exist
3284 + * previous to the call, respectively.
3285 + *
3286 + * Returns 0, or a negative error number on failure.
3287 + */
3288 +int
3289 +ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
3290 +              const char *name, const void *value, size_t value_len, int flags)
3291 +{
3292 +       struct super_block *sb = inode->i_sb;
3293 +       struct buffer_head *bh = NULL;
3294 +       struct ext3_xattr_header *header = NULL;
3295 +       struct ext3_xattr_entry *here, *last;
3296 +       unsigned int name_len;
3297 +       int block = EXT3_I(inode)->i_file_acl;
3298 +       int min_offs = sb->s_blocksize, not_found = 1, free, error;
3299 +       char *end;
3300 +       
3301 +       /*
3302 +        * header -- Points either into bh, or to a temporarily
3303 +        *           allocated buffer.
3304 +        * here -- The named entry found, or the place for inserting, within
3305 +        *         the block pointed to by header.
3306 +        * last -- Points right after the last named entry within the block
3307 +        *         pointed to by header.
3308 +        * min_offs -- The offset of the first value (values are aligned
3309 +        *             towards the end of the block).
3310 +        * end -- Points right after the block pointed to by header.
3311 +        */
3312 +       
3313 +       ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
3314 +                 name_index, name, value, (long)value_len);
3315 +
3316 +       if (IS_RDONLY(inode))
3317 +               return -EROFS;
3318 +       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
3319 +               return -EPERM;
3320 +       if (value == NULL)
3321 +               value_len = 0;
3322 +       if (name == NULL)
3323 +               return -EINVAL;
3324 +       name_len = strlen(name);
3325 +       if (name_len > 255 || value_len > sb->s_blocksize)
3326 +               return -ERANGE;
3327 +       down(&ext3_xattr_sem);
3328 +
3329 +       if (block) {
3330 +               /* The inode already has an extended attribute block. */
3331 +               bh = sb_bread(sb, block);
3332 +               error = -EIO;
3333 +               if (!bh)
3334 +                       goto cleanup;
3335 +               ea_bdebug(bh, "b_count=%d, refcount=%d",
3336 +                       atomic_read(&(bh->b_count)),
3337 +                       le32_to_cpu(HDR(bh)->h_refcount));
3338 +               header = HDR(bh);
3339 +               end = bh->b_data + bh->b_size;
3340 +               if (header->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
3341 +                   header->h_blocks != cpu_to_le32(1)) {
3342 +bad_block:             ext3_error(sb, "ext3_xattr_set",
3343 +                               "inode %ld: bad block %d", inode->i_ino, block);
3344 +                       error = -EIO;
3345 +                       goto cleanup;
3346 +               }
3347 +               /* Find the named attribute. */
3348 +               here = FIRST_ENTRY(bh);
3349 +               while (!IS_LAST_ENTRY(here)) {
3350 +                       struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(here);
3351 +                       if ((char *)next >= end)
3352 +                               goto bad_block;
3353 +                       if (!here->e_value_block && here->e_value_size) {
3354 +                               int offs = le16_to_cpu(here->e_value_offs);
3355 +                               if (offs < min_offs)
3356 +                                       min_offs = offs;
3357 +                       }
3358 +                       not_found = name_index - here->e_name_index;
3359 +                       if (!not_found)
3360 +                               not_found = name_len - here->e_name_len;
3361 +                       if (!not_found)
3362 +                               not_found = memcmp(name, here->e_name,name_len);
3363 +                       if (not_found <= 0)
3364 +                               break;
3365 +                       here = next;
3366 +               }
3367 +               last = here;
3368 +               /* We still need to compute min_offs and last. */
3369 +               while (!IS_LAST_ENTRY(last)) {
3370 +                       struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
3371 +                       if ((char *)next >= end)
3372 +                               goto bad_block;
3373 +                       if (!last->e_value_block && last->e_value_size) {
3374 +                               int offs = le16_to_cpu(last->e_value_offs);
3375 +                               if (offs < min_offs)
3376 +                                       min_offs = offs;
3377 +                       }
3378 +                       last = next;
3379 +               }
3380 +
3381 +               /* Check whether we have enough space left. */
3382 +               free = min_offs - ((char*)last - (char*)header) - sizeof(__u32);
3383 +       } else {
3384 +               /* We will use a new extended attribute block. */
3385 +               free = sb->s_blocksize -
3386 +                       sizeof(struct ext3_xattr_header) - sizeof(__u32);
3387 +               here = last = NULL;  /* avoid gcc uninitialized warning. */
3388 +       }
3389 +
3390 +       if (not_found) {
3391 +               /* Request to remove a nonexistent attribute? */
3392 +               error = -ENOATTR;
3393 +               if (flags & XATTR_REPLACE)
3394 +                       goto cleanup;
3395 +               error = 0;
3396 +               if (value == NULL)
3397 +                       goto cleanup;
3398 +               else
3399 +                       free -= EXT3_XATTR_LEN(name_len);
3400 +       } else {
3401 +               /* Request to create an existing attribute? */
3402 +               error = -EEXIST;
3403 +               if (flags & XATTR_CREATE)
3404 +                       goto cleanup;
3405 +               if (!here->e_value_block && here->e_value_size) {
3406 +                       unsigned int size = le32_to_cpu(here->e_value_size);
3407 +
3408 +                       if (le16_to_cpu(here->e_value_offs) + size > 
3409 +                           sb->s_blocksize || size > sb->s_blocksize)
3410 +                               goto bad_block;
3411 +                       free += EXT3_XATTR_SIZE(size);
3412 +               }
3413 +       }
3414 +       free -= EXT3_XATTR_SIZE(value_len);
3415 +       error = -ENOSPC;
3416 +       if (free < 0)
3417 +               goto cleanup;
3418 +
3419 +       /* Here we know that we can set the new attribute. */
3420 +
3421 +       if (header) {
3422 +               if (header->h_refcount == cpu_to_le32(1)) {
3423 +                       ea_bdebug(bh, "modifying in-place");
3424 +                       ext3_xattr_cache_remove(bh);
3425 +                       error = ext3_journal_get_write_access(handle, bh);
3426 +                       if (error)
3427 +                               goto cleanup;
3428 +               } else {
3429 +                       int offset;
3430 +
3431 +                       ea_bdebug(bh, "cloning");
3432 +                       header = kmalloc(bh->b_size, GFP_KERNEL);
3433 +                       error = -ENOMEM;
3434 +                       if (header == NULL)
3435 +                               goto cleanup;
3436 +                       memcpy(header, HDR(bh), bh->b_size);
3437 +                       header->h_refcount = cpu_to_le32(1);
3438 +                       offset = (char *)header - bh->b_data;
3439 +                       here = ENTRY((char *)here + offset);
3440 +                       last = ENTRY((char *)last + offset);
3441 +               }
3442 +       } else {
3443 +               /* Allocate a buffer where we construct the new block. */
3444 +               header = kmalloc(sb->s_blocksize, GFP_KERNEL);
3445 +               error = -ENOMEM;
3446 +               if (header == NULL)
3447 +                       goto cleanup;
3448 +               memset(header, 0, sb->s_blocksize);
3449 +               end = (char *)header + sb->s_blocksize;
3450 +               header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC);
3451 +               header->h_blocks = header->h_refcount = cpu_to_le32(1);
3452 +               last = here = ENTRY(header+1);
3453 +       }
3454 +
3455 +       if (not_found) {
3456 +               /* Insert the new name. */
3457 +               int size = EXT3_XATTR_LEN(name_len);
3458 +               int rest = (char *)last - (char *)here;
3459 +               memmove((char *)here + size, here, rest);
3460 +               memset(here, 0, size);
3461 +               here->e_name_index = name_index;
3462 +               here->e_name_len = name_len;
3463 +               memcpy(here->e_name, name, name_len);
3464 +       } else {
3465 +               /* Remove the old value. */
3466 +               if (!here->e_value_block && here->e_value_size) {
3467 +                       char *first_val = (char *)header + min_offs;
3468 +                       int offs = le16_to_cpu(here->e_value_offs);
3469 +                       char *val = (char *)header + offs;
3470 +                       size_t size = EXT3_XATTR_SIZE(
3471 +                               le32_to_cpu(here->e_value_size));
3472 +                       memmove(first_val + size, first_val, val - first_val);
3473 +                       memset(first_val, 0, size);
3474 +                       here->e_value_offs = 0;
3475 +                       min_offs += size;
3476 +
3477 +                       /* Adjust all value offsets. */
3478 +                       last = ENTRY(header+1);
3479 +                       while (!IS_LAST_ENTRY(last)) {
3480 +                               int o = le16_to_cpu(last->e_value_offs);
3481 +                               if (!last->e_value_block && o < offs)
3482 +                                       last->e_value_offs =
3483 +                                               cpu_to_le16(o + size);
3484 +                               last = EXT3_XATTR_NEXT(last);
3485 +                       }
3486 +               }
3487 +               if (value == NULL) {
3488 +                       /* Remove this attribute. */
3489 +                       if (EXT3_XATTR_NEXT(ENTRY(header+1)) == last) {
3490 +                               /* This block is now empty. */
3491 +                               error = ext3_xattr_set2(handle, inode, bh,NULL);
3492 +                               goto cleanup;
3493 +                       } else {
3494 +                               /* Remove the old name. */
3495 +                               int size = EXT3_XATTR_LEN(name_len);
3496 +                               last = ENTRY((char *)last - size);
3497 +                               memmove(here, (char*)here + size,
3498 +                                       (char*)last - (char*)here);
3499 +                               memset(last, 0, size);
3500 +                       }
3501 +               }
3502 +       }
3503 +
3504 +       if (value != NULL) {
3505 +               /* Insert the new value. */
3506 +               here->e_value_size = cpu_to_le32(value_len);
3507 +               if (value_len) {
3508 +                       size_t size = EXT3_XATTR_SIZE(value_len);
3509 +                       char *val = (char *)header + min_offs - size;
3510 +                       here->e_value_offs =
3511 +                               cpu_to_le16((char *)val - (char *)header);
3512 +                       memset(val + size - EXT3_XATTR_PAD, 0,
3513 +                              EXT3_XATTR_PAD); /* Clear the pad bytes. */
3514 +                       memcpy(val, value, value_len);
3515 +               }
3516 +       }
3517 +       ext3_xattr_rehash(header, here);
3518 +
3519 +       error = ext3_xattr_set2(handle, inode, bh, header);
3520 +
3521 +cleanup:
3522 +       brelse(bh);
3523 +       if (!(bh && header == HDR(bh)))
3524 +               kfree(header);
3525 +       up(&ext3_xattr_sem);
3526 +
3527 +       return error;
3528 +}
3529 +
3530 +/*
3531 + * Second half of ext3_xattr_set(): Update the file system.
3532 + */
3533 +static int
3534 +ext3_xattr_set2(handle_t *handle, struct inode *inode,
3535 +               struct buffer_head *old_bh, struct ext3_xattr_header *header)
3536 +{
3537 +       struct super_block *sb = inode->i_sb;
3538 +       struct buffer_head *new_bh = NULL;
3539 +       int error;
3540 +
3541 +       if (header) {
3542 +               new_bh = ext3_xattr_cache_find(inode, header);
3543 +               if (new_bh) {
3544 +                       /*
3545 +                        * We found an identical block in the cache.
3546 +                        * The old block will be released after updating
3547 +                        * the inode.
3548 +                        */
3549 +                       ea_bdebug(old_bh, "reusing block %ld",
3550 +                               new_bh->b_blocknr);
3551 +                       
3552 +                       error = -EDQUOT;
3553 +                       if (ext3_xattr_quota_alloc(inode, 1))
3554 +                               goto cleanup;
3555 +                       
3556 +                       error = ext3_journal_get_write_access(handle, new_bh);
3557 +                       if (error)
3558 +                               goto cleanup;
3559 +                       HDR(new_bh)->h_refcount = cpu_to_le32(
3560 +                               le32_to_cpu(HDR(new_bh)->h_refcount) + 1);
3561 +                       ea_bdebug(new_bh, "refcount now=%d",
3562 +                               le32_to_cpu(HDR(new_bh)->h_refcount));
3563 +               } else if (old_bh && header == HDR(old_bh)) {
3564 +                       /* Keep this block. */
3565 +                       new_bh = old_bh;
3566 +                       ext3_xattr_cache_insert(new_bh);
3567 +               } else {
3568 +                       /* We need to allocate a new block */
3569 +                       int force = EXT3_I(inode)->i_file_acl != 0;
3570 +                       int block = ext3_xattr_new_block(handle, inode,
3571 +                                                        &error, force);
3572 +                       if (error)
3573 +                               goto cleanup;
3574 +                       ea_idebug(inode, "creating block %d", block);
3575 +
3576 +                       new_bh = sb_getblk(sb, block);
3577 +                       if (!new_bh) {
3578 +getblk_failed:                 ext3_xattr_free_block(handle, inode, block);
3579 +                               error = -EIO;
3580 +                               goto cleanup;
3581 +                       }
3582 +                       lock_buffer(new_bh);
3583 +                       error = ext3_journal_get_create_access(handle, new_bh);
3584 +                       if (error) {
3585 +                               unlock_buffer(new_bh);
3586 +                               goto getblk_failed;
3587 +                       }
3588 +                       memcpy(new_bh->b_data, header, new_bh->b_size);
3589 +                       mark_buffer_uptodate(new_bh, 1);
3590 +                       unlock_buffer(new_bh);
3591 +                       ext3_xattr_cache_insert(new_bh);
3592 +                       
3593 +                       ext3_xattr_update_super_block(handle, sb);
3594 +               }
3595 +               error = ext3_journal_dirty_metadata(handle, new_bh);
3596 +               if (error)
3597 +                       goto cleanup;
3598 +       }
3599 +
3600 +       /* Update the inode. */
3601 +       EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
3602 +       inode->i_ctime = CURRENT_TIME;
3603 +       ext3_mark_inode_dirty(handle, inode);
3604 +       if (IS_SYNC(inode))
3605 +               handle->h_sync = 1;
3606 +
3607 +       error = 0;
3608 +       if (old_bh && old_bh != new_bh) {
3609 +               /*
3610 +                * If there was an old block, and we are not still using it,
3611 +                * we now release the old block.
3612 +               */
3613 +               unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount);
3614 +
3615 +               error = ext3_journal_get_write_access(handle, old_bh);
3616 +               if (error)
3617 +                       goto cleanup;
3618 +               if (refcount == 1) {
3619 +                       /* Free the old block. */
3620 +                       ea_bdebug(old_bh, "freeing");
3621 +                       ext3_xattr_free_block(handle, inode, old_bh->b_blocknr);
3622 +
3623 +                       /* ext3_forget() calls bforget() for us, but we
3624 +                          let our caller release old_bh, so we need to
3625 +                          duplicate the handle before. */
3626 +                       get_bh(old_bh);
3627 +                       ext3_forget(handle, 1, inode, old_bh,old_bh->b_blocknr);
3628 +               } else {
3629 +                       /* Decrement the refcount only. */
3630 +                       refcount--;
3631 +                       HDR(old_bh)->h_refcount = cpu_to_le32(refcount);
3632 +                       ext3_xattr_quota_free(inode);
3633 +                       ext3_journal_dirty_metadata(handle, old_bh);
3634 +                       ea_bdebug(old_bh, "refcount now=%d", refcount);
3635 +               }
3636 +       }
3637 +
3638 +cleanup:
3639 +       if (old_bh != new_bh)
3640 +               brelse(new_bh);
3641 +
3642 +       return error;
3643 +}
3644 +
3645 +/*
3646 + * ext3_xattr_delete_inode()
3647 + *
3648 + * Free extended attribute resources associated with this inode. This
3649 + * is called immediately before an inode is freed.
3650 + */
3651 +void
3652 +ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
3653 +{
3654 +       struct buffer_head *bh;
3655 +       unsigned int block = EXT3_I(inode)->i_file_acl;
3656 +
3657 +       if (!block)
3658 +               return;
3659 +       down(&ext3_xattr_sem);
3660 +
3661 +       bh = sb_bread(inode->i_sb, block);
3662 +       if (!bh) {
3663 +               ext3_error(inode->i_sb, "ext3_xattr_delete_inode",
3664 +                       "inode %ld: block %d read error", inode->i_ino, block);
3665 +               goto cleanup;
3666 +       }
3667 +       ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count)));
3668 +       if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
3669 +           HDR(bh)->h_blocks != cpu_to_le32(1)) {
3670 +               ext3_error(inode->i_sb, "ext3_xattr_delete_inode",
3671 +                       "inode %ld: bad block %d", inode->i_ino, block);
3672 +               goto cleanup;
3673 +       }
3674 +       ext3_journal_get_write_access(handle, bh);
3675 +       ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
3676 +       if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
3677 +               ext3_xattr_cache_remove(bh);
3678 +               ext3_xattr_free_block(handle, inode, block);
3679 +               ext3_forget(handle, 1, inode, bh, block);
3680 +               bh = NULL;
3681 +       } else {
3682 +               HDR(bh)->h_refcount = cpu_to_le32(
3683 +                       le32_to_cpu(HDR(bh)->h_refcount) - 1);
3684 +               ext3_journal_dirty_metadata(handle, bh);
3685 +               if (IS_SYNC(inode))
3686 +                       handle->h_sync = 1;
3687 +               ext3_xattr_quota_free(inode);
3688 +       }
3689 +       EXT3_I(inode)->i_file_acl = 0;
3690 +
3691 +cleanup:
3692 +       brelse(bh);
3693 +       up(&ext3_xattr_sem);
3694 +}
3695 +
3696 +/*
3697 + * ext3_xattr_put_super()
3698 + *
3699 + * This is called when a file system is unmounted.
3700 + */
3701 +void
3702 +ext3_xattr_put_super(struct super_block *sb)
3703 +{
3704 +#ifdef CONFIG_EXT3_FS_XATTR_SHARING
3705 +       mb_cache_shrink(ext3_xattr_cache, sb->s_dev);
3706 +#endif
3707 +}
3708 +
3709 +#ifdef CONFIG_EXT3_FS_XATTR_SHARING
3710 +
3711 +/*
3712 + * ext3_xattr_cache_insert()
3713 + *
3714 + * Create a new entry in the extended attribute cache, and insert
3715 + * it unless such an entry is already in the cache.
3716 + *
3717 + * Returns 0, or a negative error number on failure.
3718 + */
3719 +static int
3720 +ext3_xattr_cache_insert(struct buffer_head *bh)
3721 +{
3722 +       __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
3723 +       struct mb_cache_entry *ce;
3724 +       int error;
3725 +
3726 +       ce = mb_cache_entry_alloc(ext3_xattr_cache);
3727 +       if (!ce)
3728 +               return -ENOMEM;
3729 +       error = mb_cache_entry_insert(ce, bh->b_dev, bh->b_blocknr, &hash);
3730 +       if (error) {
3731 +               mb_cache_entry_free(ce);
3732 +               if (error == -EBUSY) {
3733 +                       ea_bdebug(bh, "already in cache (%d cache entries)",
3734 +                               atomic_read(&ext3_xattr_cache->c_entry_count));
3735 +                       error = 0;
3736 +               }
3737 +       } else {
3738 +               ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
3739 +                         atomic_read(&ext3_xattr_cache->c_entry_count));
3740 +               mb_cache_entry_release(ce);
3741 +       }
3742 +       return error;
3743 +}
3744 +
3745 +/*
3746 + * ext3_xattr_cmp()
3747 + *
3748 + * Compare two extended attribute blocks for equality.
3749 + *
3750 + * Returns 0 if the blocks are equal, 1 if they differ, and
3751 + * a negative error number on errors.
3752 + */
3753 +static int
3754 +ext3_xattr_cmp(struct ext3_xattr_header *header1,
3755 +              struct ext3_xattr_header *header2)
3756 +{
3757 +       struct ext3_xattr_entry *entry1, *entry2;
3758 +
3759 +       entry1 = ENTRY(header1+1);
3760 +       entry2 = ENTRY(header2+1);
3761 +       while (!IS_LAST_ENTRY(entry1)) {
3762 +               if (IS_LAST_ENTRY(entry2))
3763 +                       return 1;
3764 +               if (entry1->e_hash != entry2->e_hash ||
3765 +                   entry1->e_name_len != entry2->e_name_len ||
3766 +                   entry1->e_value_size != entry2->e_value_size ||
3767 +                   memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
3768 +                       return 1;
3769 +               if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
3770 +                       return -EIO;
3771 +               if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
3772 +                          (char *)header2 + le16_to_cpu(entry2->e_value_offs),
3773 +                          le32_to_cpu(entry1->e_value_size)))
3774 +                       return 1;
3775 +
3776 +               entry1 = EXT3_XATTR_NEXT(entry1);
3777 +               entry2 = EXT3_XATTR_NEXT(entry2);
3778 +       }
3779 +       if (!IS_LAST_ENTRY(entry2))
3780 +               return 1;
3781 +       return 0;
3782 +}
3783 +
3784 +/*
3785 + * ext3_xattr_cache_find()
3786 + *
3787 + * Find an identical extended attribute block.
3788 + *
3789 + * Returns a pointer to the block found, or NULL if such a block was
3790 + * not found or an error occurred.
3791 + */
3792 +static struct buffer_head *
3793 +ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header)
3794 +{
3795 +       __u32 hash = le32_to_cpu(header->h_hash);
3796 +       struct mb_cache_entry *ce;
3797 +
3798 +       if (!header->h_hash)
3799 +               return NULL;  /* never share */
3800 +       ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
3801 +       ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, inode->i_dev, hash);
3802 +       while (ce) {
3803 +               struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block);
3804 +
3805 +               if (!bh) {
3806 +                       ext3_error(inode->i_sb, "ext3_xattr_cache_find",
3807 +                               "inode %ld: block %ld read error",
3808 +                               inode->i_ino, ce->e_block);
3809 +               } else if (le32_to_cpu(HDR(bh)->h_refcount) >
3810 +                          EXT3_XATTR_REFCOUNT_MAX) {
3811 +                       ea_idebug(inode, "block %ld refcount %d>%d",ce->e_block,
3812 +                               le32_to_cpu(HDR(bh)->h_refcount),
3813 +                               EXT3_XATTR_REFCOUNT_MAX);
3814 +               } else if (!ext3_xattr_cmp(header, HDR(bh))) {
3815 +                       ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count)));
3816 +                       mb_cache_entry_release(ce);
3817 +                       return bh;
3818 +               }
3819 +               brelse(bh);
3820 +               ce = mb_cache_entry_find_next(ce, 0, inode->i_dev, hash);
3821 +       }
3822 +       return NULL;
3823 +}
3824 +
3825 +/*
3826 + * ext3_xattr_cache_remove()
3827 + *
3828 + * Remove the cache entry of a block from the cache. Called when a
3829 + * block becomes invalid.
3830 + */
3831 +static void
3832 +ext3_xattr_cache_remove(struct buffer_head *bh)
3833 +{
3834 +       struct mb_cache_entry *ce;
3835 +
3836 +       ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_dev, bh->b_blocknr);
3837 +       if (ce) {
3838 +               ea_bdebug(bh, "removing (%d cache entries remaining)",
3839 +                         atomic_read(&ext3_xattr_cache->c_entry_count)-1);
3840 +               mb_cache_entry_free(ce);
3841 +       } else 
3842 +               ea_bdebug(bh, "no cache entry");
3843 +}
3844 +
3845 +#define NAME_HASH_SHIFT 5
3846 +#define VALUE_HASH_SHIFT 16
3847 +
3848 +/*
3849 + * ext3_xattr_hash_entry()
3850 + *
3851 + * Compute the hash of an extended attribute.
3852 + */
3853 +static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header,
3854 +                                        struct ext3_xattr_entry *entry)
3855 +{
3856 +       __u32 hash = 0;
3857 +       char *name = entry->e_name;
3858 +       int n;
3859 +
3860 +       for (n=0; n < entry->e_name_len; n++) {
3861 +               hash = (hash << NAME_HASH_SHIFT) ^
3862 +                      (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
3863 +                      *name++;
3864 +       }
3865 +
3866 +       if (entry->e_value_block == 0 && entry->e_value_size != 0) {
3867 +               __u32 *value = (__u32 *)((char *)header +
3868 +                       le16_to_cpu(entry->e_value_offs));
3869 +               for (n = (le32_to_cpu(entry->e_value_size) +
3870 +                    EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) {
3871 +                       hash = (hash << VALUE_HASH_SHIFT) ^
3872 +                              (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
3873 +                              le32_to_cpu(*value++);
3874 +               }
3875 +       }
3876 +       entry->e_hash = cpu_to_le32(hash);
3877 +}
3878 +
3879 +#undef NAME_HASH_SHIFT
3880 +#undef VALUE_HASH_SHIFT
3881 +
3882 +#define BLOCK_HASH_SHIFT 16
3883 +
3884 +/*
3885 + * ext3_xattr_rehash()
3886 + *
3887 + * Re-compute the extended attribute hash value after an entry has changed.
3888 + */
3889 +static void ext3_xattr_rehash(struct ext3_xattr_header *header,
3890 +                             struct ext3_xattr_entry *entry)
3891 +{
3892 +       struct ext3_xattr_entry *here;
3893 +       __u32 hash = 0;
3894 +       
3895 +       ext3_xattr_hash_entry(header, entry);
3896 +       here = ENTRY(header+1);
3897 +       while (!IS_LAST_ENTRY(here)) {
3898 +               if (!here->e_hash) {
3899 +                       /* Block is not shared if an entry's hash value == 0 */
3900 +                       hash = 0;
3901 +                       break;
3902 +               }
3903 +               hash = (hash << BLOCK_HASH_SHIFT) ^
3904 +                      (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
3905 +                      le32_to_cpu(here->e_hash);
3906 +               here = EXT3_XATTR_NEXT(here);
3907 +       }
3908 +       header->h_hash = cpu_to_le32(hash);
3909 +}
3910 +
3911 +#undef BLOCK_HASH_SHIFT
3912 +
3913 +int __init
3914 +init_ext3_xattr(void)
3915 +{
3916 +       ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL,
3917 +               sizeof(struct mb_cache_entry) +
3918 +               sizeof(struct mb_cache_entry_index), 1, 61);
3919 +       if (!ext3_xattr_cache)
3920 +               return -ENOMEM;
3921 +
3922 +       return 0;
3923 +}
3924 +
3925 +void
3926 +exit_ext3_xattr(void)
3927 +{
3928 +       if (ext3_xattr_cache)
3929 +               mb_cache_destroy(ext3_xattr_cache);
3930 +       ext3_xattr_cache = NULL;
3931 +}
3932 +
3933 +#else  /* CONFIG_EXT3_FS_XATTR_SHARING */
3934 +
3935 +int __init
3936 +init_ext3_xattr(void)
3937 +{
3938 +       return 0;
3939 +}
3940 +
3941 +void
3942 +exit_ext3_xattr(void)
3943 +{
3944 +}
3945 +
3946 +#endif  /* CONFIG_EXT3_FS_XATTR_SHARING */
3947 Index: linux-2.4.19-pre1/fs/ext3/xattr_user.c
3948 ===================================================================
3949 --- linux-2.4.19-pre1.orig/fs/ext3/xattr_user.c 2003-01-30 13:24:37.000000000 +0300
3950 +++ linux-2.4.19-pre1/fs/ext3/xattr_user.c      2004-01-14 01:11:49.000000000 +0300
3951 @@ -0,0 +1,111 @@
3952 +/*
3953 + * linux/fs/ext3/xattr_user.c
3954 + * Handler for extended user attributes.
3955 + *
3956 + * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
3957 + */
3958 +
3959 +#include <linux/module.h>
3960 +#include <linux/string.h>
3961 +#include <linux/fs.h>
3962 +#include <linux/ext3_jbd.h>
3963 +#include <linux/ext3_fs.h>
3964 +#include <linux/ext3_xattr.h>
3965 +
3966 +#ifdef CONFIG_EXT3_FS_POSIX_ACL
3967 +# include <linux/ext3_acl.h>
3968 +#endif
3969 +
3970 +#define XATTR_USER_PREFIX "user."
3971 +
3972 +static size_t
3973 +ext3_xattr_user_list(char *list, struct inode *inode,
3974 +                    const char *name, int name_len)
3975 +{
3976 +       const int prefix_len = sizeof(XATTR_USER_PREFIX)-1;
3977 +
3978 +       if (!test_opt(inode->i_sb, XATTR_USER))
3979 +               return 0;
3980 +
3981 +       if (list) {
3982 +               memcpy(list, XATTR_USER_PREFIX, prefix_len);
3983 +               memcpy(list+prefix_len, name, name_len);
3984 +               list[prefix_len + name_len] = '\0';
3985 +       }
3986 +       return prefix_len + name_len + 1;
3987 +}
3988 +
3989 +static int
3990 +ext3_xattr_user_get(struct inode *inode, const char *name,
3991 +                   void *buffer, size_t size)
3992 +{
3993 +       int error;
3994 +
3995 +       if (strcmp(name, "") == 0)
3996 +               return -EINVAL;
3997 +       if (!test_opt(inode->i_sb, XATTR_USER))
3998 +               return -ENOTSUP;
3999 +#ifdef CONFIG_EXT3_FS_POSIX_ACL
4000 +       error = ext3_permission_locked(inode, MAY_READ);
4001 +#else
4002 +       error = permission(inode, MAY_READ);
4003 +#endif
4004 +       if (error)
4005 +               return error;
4006 +
4007 +       return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name,
4008 +                             buffer, size);
4009 +}
4010 +
4011 +static int
4012 +ext3_xattr_user_set(struct inode *inode, const char *name,
4013 +                   const void *value, size_t size, int flags)
4014 +{
4015 +       handle_t *handle;
4016 +       int error;
4017 +
4018 +       if (strcmp(name, "") == 0)
4019 +               return -EINVAL;
4020 +       if (!test_opt(inode->i_sb, XATTR_USER))
4021 +               return -ENOTSUP;
4022 +       if ( !S_ISREG(inode->i_mode) &&
4023 +           (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
4024 +               return -EPERM;
4025 +#ifdef CONFIG_EXT3_FS_POSIX_ACL
4026 +       error = ext3_permission_locked(inode, MAY_WRITE);
4027 +#else
4028 +       error = permission(inode, MAY_WRITE);
4029 +#endif
4030 +       if (error)
4031 +               return error;
4032 +
4033 +       handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
4034 +       if (IS_ERR(handle))
4035 +               return PTR_ERR(handle);
4036 +       error = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_USER, name,
4037 +                              value, size, flags);
4038 +       ext3_journal_stop(handle, inode);
4039 +
4040 +       return error;
4041 +}
4042 +
4043 +struct ext3_xattr_handler ext3_xattr_user_handler = {
4044 +       prefix: XATTR_USER_PREFIX,
4045 +       list:   ext3_xattr_user_list,
4046 +       get:    ext3_xattr_user_get,
4047 +       set:    ext3_xattr_user_set,
4048 +};
4049 +
4050 +int __init
4051 +init_ext3_xattr_user(void)
4052 +{
4053 +       return ext3_xattr_register(EXT3_XATTR_INDEX_USER,
4054 +                                  &ext3_xattr_user_handler);
4055 +}
4056 +
4057 +void
4058 +exit_ext3_xattr_user(void)
4059 +{
4060 +       ext3_xattr_unregister(EXT3_XATTR_INDEX_USER,
4061 +                             &ext3_xattr_user_handler);
4062 +}
4063 Index: linux-2.4.19-pre1/fs/ext3/ext3-exports.c
4064 ===================================================================
4065 --- linux-2.4.19-pre1.orig/fs/ext3/ext3-exports.c       2003-01-30 13:24:37.000000000 +0300
4066 +++ linux-2.4.19-pre1/fs/ext3/ext3-exports.c    2004-01-14 01:11:49.000000000 +0300
4067 @@ -0,0 +1,13 @@
4068 +#include <linux/config.h>
4069 +#include <linux/module.h>
4070 +#include <linux/ext3_fs.h>
4071 +#include <linux/ext3_jbd.h>
4072 +#include <linux/ext3_xattr.h>
4073 +
4074 +EXPORT_SYMBOL(ext3_force_commit);
4075 +EXPORT_SYMBOL(ext3_bread);
4076 +EXPORT_SYMBOL(ext3_xattr_register);
4077 +EXPORT_SYMBOL(ext3_xattr_unregister);
4078 +EXPORT_SYMBOL(ext3_xattr_get);
4079 +EXPORT_SYMBOL(ext3_xattr_list);
4080 +EXPORT_SYMBOL(ext3_xattr_set);
4081 Index: linux-2.4.19-pre1/fs/mbcache.c
4082 ===================================================================
4083 --- linux-2.4.19-pre1.orig/fs/mbcache.c 2003-01-30 13:24:37.000000000 +0300
4084 +++ linux-2.4.19-pre1/fs/mbcache.c      2004-01-14 01:11:49.000000000 +0300
4085 @@ -0,0 +1,648 @@
4086 +/*
4087 + * linux/fs/mbcache.c
4088 + * (C) 2001-2002 Andreas Gruenbacher, <a.gruenbacher@computer.org>
4089 + */
4090 +
4091 +/*
4092 + * Filesystem Meta Information Block Cache (mbcache)
4093 + *
4094 + * The mbcache caches blocks of block devices that need to be located
4095 + * by their device/block number, as well as by other criteria (such
4096 + * as the block's contents).
4097 + *
4098 + * There can only be one cache entry in a cache per device and block number.
4099 + * Additional indexes need not be unique in this sense. The number of
4100 + * additional indexes (=other criteria) can be hardwired at compile time
4101 + * or specified at cache create time.
4102 + *
4103 + * Each cache entry is of fixed size. An entry may be `valid' or `invalid'
4104 + * in the cache. A valid entry is in the main hash tables of the cache,
4105 + * and may also be in the lru list. An invalid entry is not in any hashes
4106 + * or lists.
4107 + *
4108 + * A valid cache entry is only in the lru list if no handles refer to it.
4109 + * Invalid cache entries will be freed when the last handle to the cache
4110 + * entry is released. Entries that cannot be freed immediately are put
4111 + * back on the lru list.
4112 + */
4113 +
4114 +#include <linux/kernel.h>
4115 +#include <linux/module.h>
4116 +
4117 +#include <linux/fs.h>
4118 +#include <linux/slab.h>
4119 +#include <linux/sched.h>
4120 +#include <linux/cache_def.h>
4121 +#include <linux/version.h>
4122 +#include <linux/init.h>
4123 +#include <linux/mbcache.h>
4124 +
4125 +
4126 +#ifdef MB_CACHE_DEBUG
4127 +# define mb_debug(f...) do { \
4128 +               printk(KERN_DEBUG f); \
4129 +               printk("\n"); \
4130 +       } while (0)
4131 +#define mb_assert(c) do { if (!(c)) \
4132 +               printk(KERN_ERR "assertion " #c " failed\n"); \
4133 +       } while(0)
4134 +#else
4135 +# define mb_debug(f...) do { } while(0)
4136 +# define mb_assert(c) do { } while(0)
4137 +#endif
4138 +#define mb_error(f...) do { \
4139 +               printk(KERN_ERR f); \
4140 +               printk("\n"); \
4141 +       } while(0)
4142 +               
4143 +MODULE_AUTHOR("Andreas Gruenbacher <a.gruenbacher@computer.org>");
4144 +MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
4145 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
4146 +MODULE_LICENSE("GPL");
4147 +#endif
4148 +
4149 +EXPORT_SYMBOL(mb_cache_create);
4150 +EXPORT_SYMBOL(mb_cache_shrink);
4151 +EXPORT_SYMBOL(mb_cache_destroy);
4152 +EXPORT_SYMBOL(mb_cache_entry_alloc);
4153 +EXPORT_SYMBOL(mb_cache_entry_insert);
4154 +EXPORT_SYMBOL(mb_cache_entry_release);
4155 +EXPORT_SYMBOL(mb_cache_entry_takeout);
4156 +EXPORT_SYMBOL(mb_cache_entry_free);
4157 +EXPORT_SYMBOL(mb_cache_entry_dup);
4158 +EXPORT_SYMBOL(mb_cache_entry_get);
4159 +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
4160 +EXPORT_SYMBOL(mb_cache_entry_find_first);
4161 +EXPORT_SYMBOL(mb_cache_entry_find_next);
4162 +#endif
4163 +
4164 +
4165 +/*
4166 + * Global data: list of all mbcache's, lru list, and a spinlock for
4167 + * accessing cache data structures on SMP machines. The lru list is
4168 + * global across all mbcaches.
4169 + */
4170 +
4171 +static LIST_HEAD(mb_cache_list);
4172 +static LIST_HEAD(mb_cache_lru_list);
4173 +static spinlock_t mb_cache_spinlock = SPIN_LOCK_UNLOCKED;
4174 +
4175 +static inline int
4176 +mb_cache_indexes(struct mb_cache *cache)
4177 +{
4178 +#ifdef MB_CACHE_INDEXES_COUNT
4179 +       return MB_CACHE_INDEXES_COUNT;
4180 +#else
4181 +       return cache->c_indexes_count;
4182 +#endif
4183 +}
4184 +
4185 +/*
4186 + * What the mbcache registers as to get shrunk dynamically.
4187 + */
4188 +
4189 +static void
4190 +mb_cache_memory_pressure(int priority, unsigned int gfp_mask);
4191 +
4192 +static struct cache_definition mb_cache_definition = {
4193 +       "mb_cache",
4194 +       mb_cache_memory_pressure
4195 +};
4196 +
4197 +
4198 +static inline int
4199 +__mb_cache_entry_is_hashed(struct mb_cache_entry *ce)
4200 +{
4201 +       return !list_empty(&ce->e_block_list);
4202 +}
4203 +
4204 +
4205 +static inline void
4206 +__mb_cache_entry_unhash(struct mb_cache_entry *ce)
4207 +{
4208 +       int n;
4209 +
4210 +       if (__mb_cache_entry_is_hashed(ce)) {
4211 +               list_del_init(&ce->e_block_list);
4212 +               for (n=0; n<mb_cache_indexes(ce->e_cache); n++)
4213 +                       list_del(&ce->e_indexes[n].o_list);
4214 +       }
4215 +}
4216 +
4217 +
4218 +static inline void
4219 +__mb_cache_entry_forget(struct mb_cache_entry *ce, int gfp_mask)
4220 +{
4221 +       struct mb_cache *cache = ce->e_cache;
4222 +
4223 +       mb_assert(atomic_read(&ce->e_used) == 0);
4224 +       if (cache->c_op.free && cache->c_op.free(ce, gfp_mask)) {
4225 +               /* free failed -- put back on the lru list
4226 +                  for freeing later. */
4227 +               spin_lock(&mb_cache_spinlock);
4228 +               list_add(&ce->e_lru_list, &mb_cache_lru_list);
4229 +               spin_unlock(&mb_cache_spinlock);
4230 +       } else {
4231 +               kmem_cache_free(cache->c_entry_cache, ce);
4232 +               atomic_dec(&cache->c_entry_count);
4233 +       }
4234 +}
4235 +
4236 +
4237 +static inline void
4238 +__mb_cache_entry_release_unlock(struct mb_cache_entry *ce)
4239 +{
4240 +       if (atomic_dec_and_test(&ce->e_used)) {
4241 +               if (__mb_cache_entry_is_hashed(ce))
4242 +                       list_add_tail(&ce->e_lru_list, &mb_cache_lru_list);
4243 +               else {
4244 +                       spin_unlock(&mb_cache_spinlock);
4245 +                       __mb_cache_entry_forget(ce, GFP_KERNEL);
4246 +                       return;
4247 +               }
4248 +       }
4249 +       spin_unlock(&mb_cache_spinlock);
4250 +}
4251 +
4252 +
4253 +/*
4254 + * mb_cache_memory_pressure()  memory pressure callback
4255 + *
4256 + * This function is called by the kernel memory management when memory
4257 + * gets low.
4258 + *
4259 + * @priority: Amount by which to shrink the cache (0 = highes priority)
4260 + * @gfp_mask: (ignored)
4261 + */
4262 +static void
4263 +mb_cache_memory_pressure(int priority, unsigned int gfp_mask)
4264 +{
4265 +       LIST_HEAD(free_list);
4266 +       struct list_head *l, *ltmp;
4267 +       int count = 0;
4268 +
4269 +       spin_lock(&mb_cache_spinlock);
4270 +       list_for_each(l, &mb_cache_list) {
4271 +               struct mb_cache *cache =
4272 +                       list_entry(l, struct mb_cache, c_cache_list);
4273 +               mb_debug("cache %s (%d)", cache->c_name,
4274 +                         atomic_read(&cache->c_entry_count));
4275 +               count += atomic_read(&cache->c_entry_count);
4276 +       }
4277 +       mb_debug("trying to free %d of %d entries",
4278 +                 count / (priority ? priority : 1), count);
4279 +       if (priority)
4280 +               count /= priority;
4281 +       while (count-- && !list_empty(&mb_cache_lru_list)) {
4282 +               struct mb_cache_entry *ce =
4283 +                       list_entry(mb_cache_lru_list.next,
4284 +                                  struct mb_cache_entry, e_lru_list);
4285 +               list_del(&ce->e_lru_list);
4286 +               __mb_cache_entry_unhash(ce);
4287 +               list_add_tail(&ce->e_lru_list, &free_list);
4288 +       }
4289 +       spin_unlock(&mb_cache_spinlock);
4290 +       list_for_each_safe(l, ltmp, &free_list) {
4291 +               __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry,
4292 +                                                  e_lru_list), gfp_mask);
4293 +       }
4294 +}
4295 +
4296 +
4297 +/*
4298 + * mb_cache_create()  create a new cache
4299 + *
4300 + * All entries in one cache are equal size. Cache entries may be from
4301 + * multiple devices. If this is the first mbcache created, registers
4302 + * the cache with kernel memory management. Returns NULL if no more
4303 + * memory was available.
4304 + *
4305 + * @name: name of the cache (informal)
4306 + * @cache_op: contains the callback called when freeing a cache entry
4307 + * @entry_size: The size of a cache entry, including
4308 + *              struct mb_cache_entry
4309 + * @indexes_count: number of additional indexes in the cache. Must equal
4310 + *                 MB_CACHE_INDEXES_COUNT if the number of indexes is
4311 + *                 hardwired.
4312 + * @bucket_count: number of hash buckets
4313 + */
4314 +struct mb_cache *
4315 +mb_cache_create(const char *name, struct mb_cache_op *cache_op,
4316 +               size_t entry_size, int indexes_count, int bucket_count)
4317 +{
4318 +       int m=0, n;
4319 +       struct mb_cache *cache = NULL;
4320 +
4321 +       if(entry_size < sizeof(struct mb_cache_entry) +
4322 +          indexes_count * sizeof(struct mb_cache_entry_index))
4323 +               return NULL;
4324 +
4325 +       MOD_INC_USE_COUNT;
4326 +       cache = kmalloc(sizeof(struct mb_cache) +
4327 +                       indexes_count * sizeof(struct list_head), GFP_KERNEL);
4328 +       if (!cache)
4329 +               goto fail;
4330 +       cache->c_name = name;
4331 +       cache->c_op.free = NULL;
4332 +       if (cache_op)
4333 +               cache->c_op.free = cache_op->free;
4334 +       atomic_set(&cache->c_entry_count, 0);
4335 +       cache->c_bucket_count = bucket_count;
4336 +#ifdef MB_CACHE_INDEXES_COUNT
4337 +       mb_assert(indexes_count == MB_CACHE_INDEXES_COUNT);
4338 +#else
4339 +       cache->c_indexes_count = indexes_count;
4340 +#endif
4341 +       cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head),
4342 +                                     GFP_KERNEL);
4343 +       if (!cache->c_block_hash)
4344 +               goto fail;
4345 +       for (n=0; n<bucket_count; n++)
4346 +               INIT_LIST_HEAD(&cache->c_block_hash[n]);
4347 +       for (m=0; m<indexes_count; m++) {
4348 +               cache->c_indexes_hash[m] = kmalloc(bucket_count *
4349 +                                                sizeof(struct list_head),
4350 +                                                GFP_KERNEL);
4351 +               if (!cache->c_indexes_hash[m])
4352 +                       goto fail;
4353 +               for (n=0; n<bucket_count; n++)
4354 +                       INIT_LIST_HEAD(&cache->c_indexes_hash[m][n]);
4355 +       }
4356 +       cache->c_entry_cache = kmem_cache_create(name, entry_size, 0,
4357 +               0 /*SLAB_POISON | SLAB_RED_ZONE*/, NULL, NULL);
4358 +       if (!cache->c_entry_cache)
4359 +               goto fail;
4360 +
4361 +       spin_lock(&mb_cache_spinlock);
4362 +       list_add(&cache->c_cache_list, &mb_cache_list);
4363 +       spin_unlock(&mb_cache_spinlock);
4364 +       return cache;
4365 +
4366 +fail:
4367 +       if (cache) {
4368 +               while (--m >= 0)
4369 +                       kfree(cache->c_indexes_hash[m]);
4370 +               if (cache->c_block_hash)
4371 +                       kfree(cache->c_block_hash);
4372 +               kfree(cache);
4373 +       }
4374 +       MOD_DEC_USE_COUNT;
4375 +       return NULL;
4376 +}
4377 +
4378 +
4379 +/*
4380 + * mb_cache_shrink()
4381 + *
4382 + * Removes all cache entires of a device from the cache. All cache entries
4383 + * currently in use cannot be freed, and thus remain in the cache.
4384 + *
4385 + * @cache: which cache to shrink
4386 + * @dev: which device's cache entries to shrink
4387 + */
4388 +void
4389 +mb_cache_shrink(struct mb_cache *cache, kdev_t dev)
4390 +{
4391 +       LIST_HEAD(free_list);
4392 +       struct list_head *l, *ltmp;
4393 +
4394 +       spin_lock(&mb_cache_spinlock);
4395 +       list_for_each_safe(l, ltmp, &mb_cache_lru_list) {
4396 +               struct mb_cache_entry *ce =
4397 +                       list_entry(l, struct mb_cache_entry, e_lru_list);
4398 +               if (ce->e_dev == dev) {
4399 +                       list_del(&ce->e_lru_list);
4400 +                       list_add_tail(&ce->e_lru_list, &free_list);
4401 +                       __mb_cache_entry_unhash(ce);
4402 +               }
4403 +       }
4404 +       spin_unlock(&mb_cache_spinlock);
4405 +       list_for_each_safe(l, ltmp, &free_list) {
4406 +               __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry,
4407 +                                                  e_lru_list), GFP_KERNEL);
4408 +       }
4409 +}
4410 +
4411 +
4412 +/*
4413 + * mb_cache_destroy()
4414 + *
4415 + * Shrinks the cache to its minimum possible size (hopefully 0 entries),
4416 + * and then destroys it. If this was the last mbcache, un-registers the
4417 + * mbcache from kernel memory management.
4418 + */
4419 +void
4420 +mb_cache_destroy(struct mb_cache *cache)
4421 +{
4422 +       LIST_HEAD(free_list);
4423 +       struct list_head *l, *ltmp;
4424 +       int n;
4425 +
4426 +       spin_lock(&mb_cache_spinlock);
4427 +       list_for_each_safe(l, ltmp, &mb_cache_lru_list) {
4428 +               struct mb_cache_entry *ce =
4429 +                       list_entry(l, struct mb_cache_entry, e_lru_list);
4430 +               if (ce->e_cache == cache) {
4431 +                       list_del(&ce->e_lru_list);
4432 +                       list_add_tail(&ce->e_lru_list, &free_list);
4433 +                       __mb_cache_entry_unhash(ce);
4434 +               }
4435 +       }
4436 +       list_del(&cache->c_cache_list);
4437 +       spin_unlock(&mb_cache_spinlock);
4438 +       list_for_each_safe(l, ltmp, &free_list) {
4439 +               __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry,
4440 +                                                  e_lru_list), GFP_KERNEL);
4441 +       }
4442 +
4443 +       if (atomic_read(&cache->c_entry_count) > 0) {
4444 +               mb_error("cache %s: %d orphaned entries",
4445 +                         cache->c_name,
4446 +                         atomic_read(&cache->c_entry_count));
4447 +       }
4448 +
4449 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
4450 +       /* We don't have kmem_cache_destroy() in 2.2.x */
4451 +       kmem_cache_shrink(cache->c_entry_cache);
4452 +#else
4453 +       kmem_cache_destroy(cache->c_entry_cache);
4454 +#endif
4455 +       for (n=0; n < mb_cache_indexes(cache); n++)
4456 +               kfree(cache->c_indexes_hash[n]);
4457 +       kfree(cache->c_block_hash);
4458 +       kfree(cache);
4459 +
4460 +       MOD_DEC_USE_COUNT;
4461 +}
4462 +
4463 +
4464 +/*
4465 + * mb_cache_entry_alloc()
4466 + *
4467 + * Allocates a new cache entry. The new entry will not be valid initially,
4468 + * and thus cannot be looked up yet. It should be filled with data, and
4469 + * then inserted into the cache using mb_cache_entry_insert(). Returns NULL
4470 + * if no more memory was available.
4471 + */
4472 +struct mb_cache_entry *
4473 +mb_cache_entry_alloc(struct mb_cache *cache)
4474 +{
4475 +       struct mb_cache_entry *ce;
4476 +
4477 +       atomic_inc(&cache->c_entry_count);
4478 +       ce = kmem_cache_alloc(cache->c_entry_cache, GFP_KERNEL);
4479 +       if (ce) {
4480 +               INIT_LIST_HEAD(&ce->e_lru_list);
4481 +               INIT_LIST_HEAD(&ce->e_block_list);
4482 +               ce->e_cache = cache;
4483 +               atomic_set(&ce->e_used, 1);
4484 +       }
4485 +       return ce;
4486 +}
4487 +
4488 +
4489 +/*
4490 + * mb_cache_entry_insert()
4491 + *
4492 + * Inserts an entry that was allocated using mb_cache_entry_alloc() into
4493 + * the cache. After this, the cache entry can be looked up, but is not yet
4494 + * in the lru list as the caller still holds a handle to it. Returns 0 on
4495 + * success, or -EBUSY if a cache entry for that device + inode exists
4496 + * already (this may happen after a failed lookup, if another process has
4497 + * inserted the same cache entry in the meantime).
4498 + *
4499 + * @dev: device the cache entry belongs to
4500 + * @block: block number
4501 + * @keys: array of additional keys. There must be indexes_count entries
4502 + *        in the array (as specified when creating the cache).
4503 + */
4504 +int
4505 +mb_cache_entry_insert(struct mb_cache_entry *ce, kdev_t dev,
4506 +                     unsigned long block, unsigned int keys[])
4507 +{
4508 +       struct mb_cache *cache = ce->e_cache;
4509 +       unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count;
4510 +       struct list_head *l;
4511 +       int error = -EBUSY, n;
4512 +
4513 +       spin_lock(&mb_cache_spinlock);
4514 +       list_for_each(l, &cache->c_block_hash[bucket]) {
4515 +               struct mb_cache_entry *ce =
4516 +                       list_entry(l, struct mb_cache_entry, e_block_list);
4517 +               if (ce->e_dev == dev && ce->e_block == block)
4518 +                       goto out;
4519 +       }
4520 +       __mb_cache_entry_unhash(ce);
4521 +       ce->e_dev = dev;
4522 +       ce->e_block = block;
4523 +       list_add(&ce->e_block_list, &cache->c_block_hash[bucket]);
4524 +       for (n=0; n<mb_cache_indexes(cache); n++) {
4525 +               ce->e_indexes[n].o_key = keys[n];
4526 +               bucket = keys[n] % cache->c_bucket_count;
4527 +               list_add(&ce->e_indexes[n].o_list,
4528 +                        &cache->c_indexes_hash[n][bucket]);
4529 +       }
4530 +out:
4531 +       spin_unlock(&mb_cache_spinlock);
4532 +       return error;
4533 +}
4534 +
4535 +
4536 +/*
4537 + * mb_cache_entry_release()
4538 + *
4539 + * Release a handle to a cache entry. When the last handle to a cache entry
4540 + * is released it is either freed (if it is invalid) or otherwise inserted
4541 + * in to the lru list.
4542 + */
4543 +void
4544 +mb_cache_entry_release(struct mb_cache_entry *ce)
4545 +{
4546 +       spin_lock(&mb_cache_spinlock);
4547 +       __mb_cache_entry_release_unlock(ce);
4548 +}
4549 +
4550 +
4551 +/*
4552 + * mb_cache_entry_takeout()
4553 + *
4554 + * Take a cache entry out of the cache, making it invalid. The entry can later
4555 + * be re-inserted using mb_cache_entry_insert(), or released using
4556 + * mb_cache_entry_release().
4557 + */
4558 +void
4559 +mb_cache_entry_takeout(struct mb_cache_entry *ce)
4560 +{
4561 +       spin_lock(&mb_cache_spinlock);
4562 +       mb_assert(list_empty(&ce->e_lru_list));
4563 +       __mb_cache_entry_unhash(ce);
4564 +       spin_unlock(&mb_cache_spinlock);
4565 +}
4566 +
4567 +
4568 +/*
4569 + * mb_cache_entry_free()
4570 + *
4571 + * This is equivalent to the sequence mb_cache_entry_takeout() --
4572 + * mb_cache_entry_release().
4573 + */
4574 +void
4575 +mb_cache_entry_free(struct mb_cache_entry *ce)
4576 +{
4577 +       spin_lock(&mb_cache_spinlock);
4578 +       mb_assert(list_empty(&ce->e_lru_list));
4579 +       __mb_cache_entry_unhash(ce);
4580 +       __mb_cache_entry_release_unlock(ce);
4581 +}
4582 +
4583 +
4584 +/*
4585 + * mb_cache_entry_dup()
4586 + *
4587 + * Duplicate a handle to a cache entry (does not duplicate the cache entry
4588 + * itself). After the call, both the old and the new handle must be released.
4589 + */
4590 +struct mb_cache_entry *
4591 +mb_cache_entry_dup(struct mb_cache_entry *ce)
4592 +{
4593 +       atomic_inc(&ce->e_used);
4594 +       return ce;
4595 +}
4596 +
4597 +
4598 +/*
4599 + * mb_cache_entry_get()
4600 + *
4601 + * Get a cache entry  by device / block number. (There can only be one entry
4602 + * in the cache per device and block.) Returns NULL if no such cache entry
4603 + * exists.
4604 + */
4605 +struct mb_cache_entry *
4606 +mb_cache_entry_get(struct mb_cache *cache, kdev_t dev, unsigned long block)
4607 +{
4608 +       unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count;
4609 +       struct list_head *l;
4610 +       struct mb_cache_entry *ce;
4611 +
4612 +       spin_lock(&mb_cache_spinlock);
4613 +       list_for_each(l, &cache->c_block_hash[bucket]) {
4614 +               ce = list_entry(l, struct mb_cache_entry, e_block_list);
4615 +               if (ce->e_dev == dev && ce->e_block == block) {
4616 +                       if (!list_empty(&ce->e_lru_list))
4617 +                               list_del_init(&ce->e_lru_list);
4618 +                       atomic_inc(&ce->e_used);
4619 +                       goto cleanup;
4620 +               }
4621 +       }
4622 +       ce = NULL;
4623 +
4624 +cleanup:
4625 +       spin_unlock(&mb_cache_spinlock);
4626 +       return ce;
4627 +}
4628 +
4629 +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
4630 +
4631 +static struct mb_cache_entry *
4632 +__mb_cache_entry_find(struct list_head *l, struct list_head *head,
4633 +                     int index, kdev_t dev, unsigned int key)
4634 +{
4635 +       while (l != head) {
4636 +               struct mb_cache_entry *ce =
4637 +                       list_entry(l, struct mb_cache_entry,
4638 +                                  e_indexes[index].o_list);
4639 +               if (ce->e_dev == dev && ce->e_indexes[index].o_key == key) {
4640 +                       if (!list_empty(&ce->e_lru_list))
4641 +                               list_del_init(&ce->e_lru_list);
4642 +                       atomic_inc(&ce->e_used);
4643 +                       return ce;
4644 +               }
4645 +               l = l->next;
4646 +       }
4647 +       return NULL;
4648 +}
4649 +
4650 +
4651 +/*
4652 + * mb_cache_entry_find_first()
4653 + *
4654 + * Find the first cache entry on a given device with a certain key in
4655 + * an additional index. Additonal matches can be found with
4656 + * mb_cache_entry_find_next(). Returns NULL if no match was found.
4657 + *
4658 + * @cache: the cache to search
4659 + * @index: the number of the additonal index to search (0<=index<indexes_count)
4660 + * @dev: the device the cache entry should belong to
4661 + * @key: the key in the index
4662 + */
4663 +struct mb_cache_entry *
4664 +mb_cache_entry_find_first(struct mb_cache *cache, int index, kdev_t dev,
4665 +                         unsigned int key)
4666 +{
4667 +       unsigned int bucket = key % cache->c_bucket_count;
4668 +       struct list_head *l;
4669 +       struct mb_cache_entry *ce;
4670 +
4671 +       mb_assert(index < mb_cache_indexes(cache));
4672 +       spin_lock(&mb_cache_spinlock);
4673 +       l = cache->c_indexes_hash[index][bucket].next;
4674 +       ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket],
4675 +                                  index, dev, key);
4676 +       spin_unlock(&mb_cache_spinlock);
4677 +       return ce;
4678 +}
4679 +
4680 +
4681 +/*
4682 + * mb_cache_entry_find_next()
4683 + *
4684 + * Find the next cache entry on a given device with a certain key in an
4685 + * additional index. Returns NULL if no match could be found. The previous
4686 + * entry is atomatically released, so that mb_cache_entry_find_next() can
4687 + * be called like this:
4688 + *
4689 + * entry = mb_cache_entry_find_first();
4690 + * while (entry) {
4691 + *     ...
4692 + *     entry = mb_cache_entry_find_next(entry, ...);
4693 + * }
4694 + *
4695 + * @prev: The previous match
4696 + * @index: the number of the additonal index to search (0<=index<indexes_count)
4697 + * @dev: the device the cache entry should belong to
4698 + * @key: the key in the index
4699 + */
4700 +struct mb_cache_entry *
4701 +mb_cache_entry_find_next(struct mb_cache_entry *prev, int index, kdev_t dev,
4702 +                        unsigned int key)
4703 +{
4704 +       struct mb_cache *cache = prev->e_cache;
4705 +       unsigned int bucket = key % cache->c_bucket_count;
4706 +       struct list_head *l;
4707 +       struct mb_cache_entry *ce;
4708 +
4709 +       mb_assert(index < mb_cache_indexes(cache));
4710 +       spin_lock(&mb_cache_spinlock);
4711 +       l = prev->e_indexes[index].o_list.next;
4712 +       ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket],
4713 +                                  index, dev, key);
4714 +       __mb_cache_entry_release_unlock(prev);
4715 +       return ce;
4716 +}
4717 +
4718 +#endif  /* !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) */
4719 +
4720 +static int __init init_mbcache(void)
4721 +{
4722 +       register_cache(&mb_cache_definition);
4723 +       return 0;
4724 +}
4725 +
4726 +static void __exit exit_mbcache(void)
4727 +{
4728 +       unregister_cache(&mb_cache_definition);
4729 +}
4730 +
4731 +module_init(init_mbcache)
4732 +module_exit(exit_mbcache)
4733 +
4734 Index: linux-2.4.19-pre1/fs/xattr.c
4735 ===================================================================
4736 --- linux-2.4.19-pre1.orig/fs/xattr.c   2003-01-30 13:24:37.000000000 +0300
4737 +++ linux-2.4.19-pre1/fs/xattr.c        2004-01-14 01:11:49.000000000 +0300
4738 @@ -0,0 +1,355 @@
4739 +/*
4740 +  File: fs/xattr.c
4741 +
4742 +  Extended attribute handling.
4743 +
4744 +  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
4745 +  Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
4746 + */
4747 +#include <linux/fs.h>
4748 +#include <linux/slab.h>
4749 +#include <linux/vmalloc.h>
4750 +#include <linux/smp_lock.h>
4751 +#include <linux/file.h>
4752 +#include <linux/xattr.h>
4753 +#include <asm/uaccess.h>
4754 +
4755 +/*
4756 + * Extended attribute memory allocation wrappers, originally
4757 + * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros.
4758 + * The vmalloc use here is very uncommon - extended attributes
4759 + * are supposed to be small chunks of metadata, and it is quite
4760 + * unusual to have very many extended attributes, so lists tend
4761 + * to be quite short as well.  The 64K upper limit is derived
4762 + * from the extended attribute size limit used by XFS.
4763 + * Intentionally allow zero @size for value/list size requests.
4764 + */
4765 +static void *
4766 +xattr_alloc(size_t size, size_t limit)
4767 +{
4768 +       void *ptr;
4769 +
4770 +       if (size > limit)
4771 +               return ERR_PTR(-E2BIG);
4772 +
4773 +       if (!size)      /* size request, no buffer is needed */
4774 +               return NULL;
4775 +       else if (size <= PAGE_SIZE)
4776 +               ptr = kmalloc((unsigned long) size, GFP_KERNEL);
4777 +       else
4778 +               ptr = vmalloc((unsigned long) size);
4779 +       if (!ptr)
4780 +               return ERR_PTR(-ENOMEM);
4781 +       return ptr;
4782 +}
4783 +
4784 +static void
4785 +xattr_free(void *ptr, size_t size)
4786 +{
4787 +       if (!size)      /* size request, no buffer was needed */
4788 +               return;
4789 +       else if (size <= PAGE_SIZE)
4790 +               kfree(ptr);
4791 +       else
4792 +               vfree(ptr);
4793 +}
4794 +
4795 +/*
4796 + * Extended attribute SET operations
4797 + */
4798 +static long
4799 +setxattr(struct dentry *d, char *name, void *value, size_t size, int flags)
4800 +{
4801 +       int error;
4802 +       void *kvalue;
4803 +       char kname[XATTR_NAME_MAX + 1];
4804 +
4805 +       if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
4806 +               return -EINVAL;
4807 +
4808 +       error = strncpy_from_user(kname, name, sizeof(kname));
4809 +       if (error == 0 || error == sizeof(kname))
4810 +               error = -ERANGE;
4811 +       if (error < 0)
4812 +               return error;
4813 +
4814 +       kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
4815 +       if (IS_ERR(kvalue))
4816 +               return PTR_ERR(kvalue);
4817 +
4818 +       if (size > 0 && copy_from_user(kvalue, value, size)) {
4819 +               xattr_free(kvalue, size);
4820 +               return -EFAULT;
4821 +       }
4822 +
4823 +       error = -EOPNOTSUPP;
4824 +       if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
4825 +               down(&d->d_inode->i_sem);
4826 +               lock_kernel();
4827 +               error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
4828 +               unlock_kernel();
4829 +               up(&d->d_inode->i_sem);
4830 +       }
4831 +
4832 +       xattr_free(kvalue, size);
4833 +       return error;
4834 +}
4835 +
4836 +asmlinkage long
4837 +sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
4838 +{
4839 +       struct nameidata nd;
4840 +       int error;
4841 +
4842 +       error = user_path_walk(path, &nd);
4843 +       if (error)
4844 +               return error;
4845 +       error = setxattr(nd.dentry, name, value, size, flags);
4846 +       path_release(&nd);
4847 +       return error;
4848 +}
4849 +
4850 +asmlinkage long
4851 +sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
4852 +{
4853 +       struct nameidata nd;
4854 +       int error;
4855 +
4856 +       error = user_path_walk_link(path, &nd);
4857 +       if (error)
4858 +               return error;
4859 +       error = setxattr(nd.dentry, name, value, size, flags);
4860 +       path_release(&nd);
4861 +       return error;
4862 +}
4863 +
4864 +asmlinkage long
4865 +sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
4866 +{
4867 +       struct file *f;
4868 +       int error = -EBADF;
4869 +
4870 +       f = fget(fd);
4871 +       if (!f)
4872 +               return error;
4873 +       error = setxattr(f->f_dentry, name, value, size, flags);
4874 +       fput(f);
4875 +       return error;
4876 +}
4877 +
4878 +/*
4879 + * Extended attribute GET operations
4880 + */
4881 +static ssize_t
4882 +getxattr(struct dentry *d, char *name, void *value, size_t size)
4883 +{
4884 +       ssize_t error;
4885 +       void *kvalue;
4886 +       char kname[XATTR_NAME_MAX + 1];
4887 +
4888 +       error = strncpy_from_user(kname, name, sizeof(kname));
4889 +       if (error == 0 || error == sizeof(kname))
4890 +               error = -ERANGE;
4891 +       if (error < 0)
4892 +               return error;
4893 +
4894 +       kvalue = xattr_alloc(size, XATTR_SIZE_MAX);
4895 +       if (IS_ERR(kvalue))
4896 +               return PTR_ERR(kvalue);
4897 +
4898 +       error = -EOPNOTSUPP;
4899 +       if (d->d_inode->i_op && d->d_inode->i_op->getxattr) {
4900 +               down(&d->d_inode->i_sem);
4901 +               lock_kernel();
4902 +               error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
4903 +               unlock_kernel();
4904 +               up(&d->d_inode->i_sem);
4905 +       }
4906 +
4907 +       if (kvalue && error > 0)
4908 +               if (copy_to_user(value, kvalue, error))
4909 +                       error = -EFAULT;
4910 +       xattr_free(kvalue, size);
4911 +       return error;
4912 +}
4913 +
4914 +asmlinkage ssize_t
4915 +sys_getxattr(char *path, char *name, void *value, size_t size)
4916 +{
4917 +       struct nameidata nd;
4918 +       ssize_t error;
4919 +
4920 +       error = user_path_walk(path, &nd);
4921 +       if (error)
4922 +               return error;
4923 +       error = getxattr(nd.dentry, name, value, size);
4924 +       path_release(&nd);
4925 +       return error;
4926 +}
4927 +
4928 +asmlinkage ssize_t
4929 +sys_lgetxattr(char *path, char *name, void *value, size_t size)
4930 +{
4931 +       struct nameidata nd;
4932 +       ssize_t error;
4933 +
4934 +       error = user_path_walk_link(path, &nd);
4935 +       if (error)
4936 +               return error;
4937 +       error = getxattr(nd.dentry, name, value, size);
4938 +       path_release(&nd);
4939 +       return error;
4940 +}
4941 +
4942 +asmlinkage ssize_t
4943 +sys_fgetxattr(int fd, char *name, void *value, size_t size)
4944 +{
4945 +       struct file *f;
4946 +       ssize_t error = -EBADF;
4947 +
4948 +       f = fget(fd);
4949 +       if (!f)
4950 +               return error;
4951 +       error = getxattr(f->f_dentry, name, value, size);
4952 +       fput(f);
4953 +       return error;
4954 +}
4955 +
4956 +/*
4957 + * Extended attribute LIST operations
4958 + */
4959 +static ssize_t
4960 +listxattr(struct dentry *d, char *list, size_t size)
4961 +{
4962 +       ssize_t error;
4963 +       char *klist;
4964 +
4965 +       klist = (char *)xattr_alloc(size, XATTR_LIST_MAX);
4966 +       if (IS_ERR(klist))
4967 +               return PTR_ERR(klist);
4968 +
4969 +       error = -EOPNOTSUPP;
4970 +       if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
4971 +               down(&d->d_inode->i_sem);
4972 +               lock_kernel();
4973 +               error = d->d_inode->i_op->listxattr(d, klist, size);
4974 +               unlock_kernel();
4975 +               up(&d->d_inode->i_sem);
4976 +       }
4977 +
4978 +       if (klist && error > 0)
4979 +               if (copy_to_user(list, klist, error))
4980 +                       error = -EFAULT;
4981 +       xattr_free(klist, size);
4982 +       return error;
4983 +}
4984 +
4985 +asmlinkage ssize_t
4986 +sys_listxattr(char *path, char *list, size_t size)
4987 +{
4988 +       struct nameidata nd;
4989 +       ssize_t error;
4990 +
4991 +       error = user_path_walk(path, &nd);
4992 +       if (error)
4993 +               return error;
4994 +       error = listxattr(nd.dentry, list, size);
4995 +       path_release(&nd);
4996 +       return error;
4997 +}
4998 +
4999 +asmlinkage ssize_t
5000 +sys_llistxattr(char *path, char *list, size_t size)
5001 +{
5002 +       struct nameidata nd;
5003 +       ssize_t error;
5004 +
5005 +       error = user_path_walk_link(path, &nd);
5006 +       if (error)
5007 +               return error;
5008 +       error = listxattr(nd.dentry, list, size);
5009 +       path_release(&nd);
5010 +       return error;
5011 +}
5012 +
5013 +asmlinkage ssize_t
5014 +sys_flistxattr(int fd, char *list, size_t size)
5015 +{
5016 +       struct file *f;
5017 +       ssize_t error = -EBADF;
5018 +
5019 +       f = fget(fd);
5020 +       if (!f)
5021 +               return error;
5022 +       error = listxattr(f->f_dentry, list, size);
5023 +       fput(f);
5024 +       return error;
5025 +}
5026 +
5027 +/*
5028 + * Extended attribute REMOVE operations
5029 + */
5030 +static long
5031 +removexattr(struct dentry *d, char *name)
5032 +{
5033 +       int error;
5034 +       char kname[XATTR_NAME_MAX + 1];
5035 +
5036 +       error = strncpy_from_user(kname, name, sizeof(kname));
5037 +       if (error == 0 || error == sizeof(kname))
5038 +               error = -ERANGE;
5039 +       if (error < 0)
5040 +               return error;
5041 +
5042 +       error = -EOPNOTSUPP;
5043 +       if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
5044 +               down(&d->d_inode->i_sem);
5045 +               lock_kernel();
5046 +               error = d->d_inode->i_op->removexattr(d, kname);
5047 +               unlock_kernel();
5048 +               up(&d->d_inode->i_sem);
5049 +       }
5050 +       return error;
5051 +}
5052 +
5053 +asmlinkage long
5054 +sys_removexattr(char *path, char *name)
5055 +{
5056 +       struct nameidata nd;
5057 +       int error;
5058 +
5059 +       error = user_path_walk(path, &nd);
5060 +       if (error)
5061 +               return error;
5062 +       error = removexattr(nd.dentry, name);
5063 +       path_release(&nd);
5064 +       return error;
5065 +}
5066 +
5067 +asmlinkage long
5068 +sys_lremovexattr(char *path, char *name)
5069 +{
5070 +       struct nameidata nd;
5071 +       int error;
5072 +
5073 +       error = user_path_walk_link(path, &nd);
5074 +       if (error)
5075 +               return error;
5076 +       error = removexattr(nd.dentry, name);
5077 +       path_release(&nd);
5078 +       return error;
5079 +}
5080 +
5081 +asmlinkage long
5082 +sys_fremovexattr(int fd, char *name)
5083 +{
5084 +       struct file *f;
5085 +       int error = -EBADF;
5086 +
5087 +       f = fget(fd);
5088 +       if (!f)
5089 +               return error;
5090 +       error = removexattr(f->f_dentry, name);
5091 +       fput(f);
5092 +       return error;
5093 +}
5094 Index: linux-2.4.19-pre1/include/asm-arm/unistd.h
5095 ===================================================================
5096 --- linux-2.4.19-pre1.orig/include/asm-arm/unistd.h     2001-08-12 22:14:00.000000000 +0400
5097 +++ linux-2.4.19-pre1/include/asm-arm/unistd.h  2004-01-14 01:11:49.000000000 +0300
5098 @@ -240,6 +240,18 @@
5099  #define __NR_mincore                   (__NR_SYSCALL_BASE+219)
5100  #define __NR_madvise                   (__NR_SYSCALL_BASE+220)
5101  #define __NR_fcntl64                   (__NR_SYSCALL_BASE+221)
5102 +#define __NR_setxattr                  (__NR_SYSCALL_BASE+226)
5103 +#define __NR_lsetxattr                 (__NR_SYSCALL_BASE+227)
5104 +#define __NR_fsetxattr                 (__NR_SYSCALL_BASE+228)
5105 +#define __NR_getxattr                  (__NR_SYSCALL_BASE+229)
5106 +#define __NR_lgetxattr                 (__NR_SYSCALL_BASE+230)
5107 +#define __NR_fgetxattr                 (__NR_SYSCALL_BASE+231)
5108 +#define __NR_listxattr                 (__NR_SYSCALL_BASE+232)
5109 +#define __NR_llistxattr                        (__NR_SYSCALL_BASE+233)
5110 +#define __NR_flistxattr                        (__NR_SYSCALL_BASE+234)
5111 +#define __NR_removexattr               (__NR_SYSCALL_BASE+235)
5112 +#define __NR_lremovexattr              (__NR_SYSCALL_BASE+236)
5113 +#define __NR_fremovexattr              (__NR_SYSCALL_BASE+237)
5114  
5115  /*
5116   * The following SWIs are ARM private.
5117 Index: linux-2.4.19-pre1/include/asm-ia64/unistd.h
5118 ===================================================================
5119 --- linux-2.4.19-pre1.orig/include/asm-ia64/unistd.h    2001-11-10 01:26:17.000000000 +0300
5120 +++ linux-2.4.19-pre1/include/asm-ia64/unistd.h 2004-01-14 01:11:49.000000000 +0300
5121 @@ -206,6 +206,18 @@
5122  #define __NR_getdents64                        1214
5123  #define __NR_getunwind                 1215
5124  #define __NR_readahead                 1216
5125 +#define __NR_setxattr                  1217
5126 +#define __NR_lsetxattr                 1218
5127 +#define __NR_fsetxattr                 1219
5128 +#define __NR_getxattr                  1220
5129 +#define __NR_lgetxattr                 1221
5130 +#define __NR_fgetxattr                 1222
5131 +#define __NR_listxattr                 1223
5132 +#define __NR_llistxattr                        1224
5133 +#define __NR_flistxattr                        1225
5134 +#define __NR_removexattr               1226
5135 +#define __NR_lremovexattr              1227
5136 +#define __NR_fremovexattr              1228
5137  
5138  #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
5139  
5140 Index: linux-2.4.19-pre1/include/asm-s390/unistd.h
5141 ===================================================================
5142 --- linux-2.4.19-pre1.orig/include/asm-s390/unistd.h    2001-10-11 20:43:38.000000000 +0400
5143 +++ linux-2.4.19-pre1/include/asm-s390/unistd.h 2004-01-14 01:11:49.000000000 +0300
5144 @@ -211,6 +211,18 @@
5145  #define __NR_mincore            218
5146  #define __NR_madvise            219
5147  #define __NR_getdents64                220
5148 +#define __NR_setxattr          224
5149 +#define __NR_lsetxattr         225
5150 +#define __NR_fsetxattr         226
5151 +#define __NR_getxattr          227
5152 +#define __NR_lgetxattr         228
5153 +#define __NR_fgetxattr         229
5154 +#define __NR_listxattr         230
5155 +#define __NR_llistxattr                231
5156 +#define __NR_flistxattr                232
5157 +#define __NR_removexattr       233
5158 +#define __NR_lremovexattr      234
5159 +#define __NR_fremovexattr      235
5160  
5161  
5162  /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
5163 Index: linux-2.4.19-pre1/include/asm-s390x/unistd.h
5164 ===================================================================
5165 --- linux-2.4.19-pre1.orig/include/asm-s390x/unistd.h   2001-10-11 20:43:38.000000000 +0400
5166 +++ linux-2.4.19-pre1/include/asm-s390x/unistd.h        2004-01-14 01:11:49.000000000 +0300
5167 @@ -181,6 +181,18 @@
5168  #define __NR_mincore            218
5169  #define __NR_madvise            219
5170  #define __NR_getdents64         220
5171 +#define __NR_setxattr          224
5172 +#define __NR_lsetxattr         225
5173 +#define __NR_fsetxattr         226
5174 +#define __NR_getxattr          227
5175 +#define __NR_lgetxattr         228
5176 +#define __NR_fgetxattr         229
5177 +#define __NR_listxattr         230
5178 +#define __NR_llistxattr                231
5179 +#define __NR_flistxattr                232
5180 +#define __NR_removexattr       233
5181 +#define __NR_lremovexattr      234
5182 +#define __NR_fremovexattr      235
5183  
5184  
5185  /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
5186 Index: linux-2.4.19-pre1/include/asm-sparc/unistd.h
5187 ===================================================================
5188 --- linux-2.4.19-pre1.orig/include/asm-sparc/unistd.h   2001-10-21 21:36:54.000000000 +0400
5189 +++ linux-2.4.19-pre1/include/asm-sparc/unistd.h        2004-01-14 01:11:49.000000000 +0300
5190 @@ -184,24 +184,24 @@
5191  /* #define __NR_exportfs        166    SunOS Specific                              */
5192  #define __NR_mount              167 /* Common                                      */
5193  #define __NR_ustat              168 /* Common                                      */
5194 -/* #define __NR_semsys          169    SunOS Specific                              */
5195 -/* #define __NR_msgsys          170    SunOS Specific                              */
5196 -/* #define __NR_shmsys          171    SunOS Specific                              */
5197 -/* #define __NR_auditsys        172    SunOS Specific                              */
5198 -/* #define __NR_rfssys          173    SunOS Specific                              */
5199 +#define __NR_setxattr           169 /* SunOS: semsys                               */
5200 +#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
5201 +#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
5202 +#define __NR_getxattr           172 /* SunOS: auditsys                             */
5203 +#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
5204  #define __NR_getdents           174 /* Common                                      */
5205  #define __NR_setsid             175 /* Common                                      */
5206  #define __NR_fchdir             176 /* Common                                      */
5207 -/* #define __NR_fchroot         177    SunOS Specific                              */
5208 -/* #define __NR_vpixsys         178    SunOS Specific                              */
5209 -/* #define __NR_aioread         179    SunOS Specific                              */
5210 -/* #define __NR_aiowrite        180    SunOS Specific                              */
5211 -/* #define __NR_aiowait         181    SunOS Specific                              */
5212 -/* #define __NR_aiocancel       182    SunOS Specific                              */
5213 +#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
5214 +#define __NR_listxattr          178 /* SunOS: vpixsys                              */
5215 +#define __NR_llistxattr         179 /* SunOS: aioread                              */
5216 +#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
5217 +#define __NR_removexattr        181 /* SunOS: aiowait                              */
5218 +#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
5219  #define __NR_sigpending         183 /* Common                                      */
5220  #define __NR_query_module      184 /* Linux Specific                              */
5221  #define __NR_setpgid            185 /* Common                                      */
5222 -/* #define __NR_pathconf        186    SunOS Specific                              */
5223 +#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
5224  /* #define __NR_fpathconf       187    SunOS Specific                              */
5225  /* #define __NR_sysconf         188    SunOS Specific                              */
5226  #define __NR_uname              189 /* Linux Specific                              */
5227 Index: linux-2.4.19-pre1/include/asm-sparc64/unistd.h
5228 ===================================================================
5229 --- linux-2.4.19-pre1.orig/include/asm-sparc64/unistd.h 2001-10-21 21:36:54.000000000 +0400
5230 +++ linux-2.4.19-pre1/include/asm-sparc64/unistd.h      2004-01-14 01:11:49.000000000 +0300
5231 @@ -184,24 +184,24 @@
5232  /* #define __NR_exportfs        166    SunOS Specific                              */
5233  #define __NR_mount              167 /* Common                                      */
5234  #define __NR_ustat              168 /* Common                                      */
5235 -/* #define __NR_semsys          169    SunOS Specific                              */
5236 -/* #define __NR_msgsys          170    SunOS Specific                              */
5237 -/* #define __NR_shmsys          171    SunOS Specific                              */
5238 -/* #define __NR_auditsys        172    SunOS Specific                              */
5239 -/* #define __NR_rfssys          173    SunOS Specific                              */
5240 +#define __NR_setxattr           169 /* SunOS: semsys                               */
5241 +#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
5242 +#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
5243 +#define __NR_getxattr           172 /* SunOS: auditsys                             */
5244 +#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
5245  #define __NR_getdents           174 /* Common                                      */
5246  #define __NR_setsid             175 /* Common                                      */
5247  #define __NR_fchdir             176 /* Common                                      */
5248 -/* #define __NR_fchroot         177    SunOS Specific                              */
5249 -/* #define __NR_vpixsys         178    SunOS Specific                              */
5250 -/* #define __NR_aioread         179    SunOS Specific                              */
5251 -/* #define __NR_aiowrite        180    SunOS Specific                              */
5252 -/* #define __NR_aiowait         181    SunOS Specific                              */
5253 -/* #define __NR_aiocancel       182    SunOS Specific                              */
5254 +#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
5255 +#define __NR_listxattr          178 /* SunOS: vpixsys                              */
5256 +#define __NR_llistxattr         179 /* SunOS: aioread                              */
5257 +#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
5258 +#define __NR_removexattr        181 /* SunOS: aiowait                              */
5259 +#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
5260  #define __NR_sigpending         183 /* Common                                      */
5261  #define __NR_query_module      184 /* Linux Specific                              */
5262  #define __NR_setpgid            185 /* Common                                      */
5263 -/* #define __NR_pathconf        186    SunOS Specific                              */
5264 +#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
5265  /* #define __NR_fpathconf       187    SunOS Specific                              */
5266  /* #define __NR_sysconf         188    SunOS Specific                              */
5267  #define __NR_uname              189 /* Linux Specific                              */
5268 Index: linux-2.4.19-pre1/include/linux/cache_def.h
5269 ===================================================================
5270 --- linux-2.4.19-pre1.orig/include/linux/cache_def.h    2003-01-30 13:24:37.000000000 +0300
5271 +++ linux-2.4.19-pre1/include/linux/cache_def.h 2004-01-14 01:11:49.000000000 +0300
5272 @@ -0,0 +1,15 @@
5273 +/*
5274 + * linux/cache_def.h
5275 + * Handling of caches defined in drivers, filesystems, ...
5276 + *
5277 + * Copyright (C) 2002 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
5278 + */
5279 +
5280 +struct cache_definition {
5281 +       const char *name;
5282 +       void (*shrink)(int, unsigned int);
5283 +       struct list_head link;
5284 +};
5285 +
5286 +extern void register_cache(struct cache_definition *);
5287 +extern void unregister_cache(struct cache_definition *);
5288 Index: linux-2.4.19-pre1/include/linux/errno.h
5289 ===================================================================
5290 --- linux-2.4.19-pre1.orig/include/linux/errno.h        2001-02-10 01:46:13.000000000 +0300
5291 +++ linux-2.4.19-pre1/include/linux/errno.h     2004-01-14 01:11:49.000000000 +0300
5292 @@ -23,4 +23,8 @@
5293  
5294  #endif
5295  
5296 +/* Defined for extended attributes */
5297 +#define ENOATTR ENODATA                /* No such attribute */
5298 +#define ENOTSUP EOPNOTSUPP     /* Operation not supported */
5299 +
5300  #endif
5301 Index: linux-2.4.19-pre1/include/linux/ext2_fs.h
5302 ===================================================================
5303 --- linux-2.4.19-pre1.orig/include/linux/ext2_fs.h      2001-11-22 22:46:52.000000000 +0300
5304 +++ linux-2.4.19-pre1/include/linux/ext2_fs.h   2004-01-14 01:18:00.000000000 +0300
5305 @@ -57,8 +57,6 @@
5306   */
5307  #define        EXT2_BAD_INO             1      /* Bad blocks inode */
5308  #define EXT2_ROOT_INO           2      /* Root inode */
5309 -#define EXT2_ACL_IDX_INO        3      /* ACL inode */
5310 -#define EXT2_ACL_DATA_INO       4      /* ACL inode */
5311  #define EXT2_BOOT_LOADER_INO    5      /* Boot loader inode */
5312  #define EXT2_UNDEL_DIR_INO      6      /* Undelete directory inode */
5313  
5314 @@ -86,7 +84,6 @@
5315  #else
5316  # define EXT2_BLOCK_SIZE(s)            (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
5317  #endif
5318 -#define EXT2_ACLE_PER_BLOCK(s)         (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
5319  #define        EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
5320  #ifdef __KERNEL__
5321  # define EXT2_BLOCK_SIZE_BITS(s)       ((s)->s_blocksize_bits)
5322 @@ -121,28 +118,6 @@
5323  #endif
5324  
5325  /*
5326 - * ACL structures
5327 - */
5328 -struct ext2_acl_header /* Header of Access Control Lists */
5329 -{
5330 -       __u32   aclh_size;
5331 -       __u32   aclh_file_count;
5332 -       __u32   aclh_acle_count;
5333 -       __u32   aclh_first_acle;
5334 -};
5335 -
5336 -struct ext2_acl_entry  /* Access Control List Entry */
5337 -{
5338 -       __u32   acle_size;
5339 -       __u16   acle_perms;     /* Access permissions */
5340 -       __u16   acle_type;      /* Type of entry */
5341 -       __u16   acle_tag;       /* User or group identity */
5342 -       __u16   acle_pad1;
5343 -       __u32   acle_next;      /* Pointer on next entry for the */
5344 -                                       /* same inode or on next free entry */
5345 -};
5346 -
5347 -/*
5348   * Structure of a blocks group descriptor
5349   */
5350  struct ext2_group_desc
5351 @@ -314,6 +289,7 @@
5352  #define EXT2_MOUNT_ERRORS_PANIC                0x0040  /* Panic on errors */
5353  #define EXT2_MOUNT_MINIX_DF            0x0080  /* Mimics the Minix statfs */
5354  #define EXT2_MOUNT_NO_UID32            0x0200  /* Disable 32-bit UIDs */
5355 +#define EXT2_MOUNT_XATTR_USER          0x4000  /* Extended user attributes */
5356  
5357  #define clear_opt(o, opt)              o &= ~EXT2_MOUNT_##opt
5358  #define set_opt(o, opt)                        o |= EXT2_MOUNT_##opt
5359 @@ -397,6 +373,7 @@
5360  
5361  #ifdef __KERNEL__
5362  #define EXT2_SB(sb)    (&((sb)->u.ext2_sb))
5363 +#define EXT2_I(inode)  (&((inode)->u.ext2_i))
5364  #else
5365  /* Assume that user mode programs are passing in an ext2fs superblock, not
5366   * a kernel struct super_block.  This will allow us to call the feature-test
5367 @@ -466,7 +443,7 @@
5368  #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV      0x0008
5369  #define EXT2_FEATURE_INCOMPAT_ANY              0xffffffff
5370  
5371 -#define EXT2_FEATURE_COMPAT_SUPP       0
5372 +#define EXT2_FEATURE_COMPAT_SUPP       EXT2_FEATURE_COMPAT_EXT_ATTR
5373  #define EXT2_FEATURE_INCOMPAT_SUPP     EXT2_FEATURE_INCOMPAT_FILETYPE
5374  #define EXT2_FEATURE_RO_COMPAT_SUPP    (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
5375                                          EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
5376 @@ -623,8 +600,10 @@
5377  
5378  /* namei.c */
5379  extern struct inode_operations ext2_dir_inode_operations;
5380 +extern struct inode_operations ext2_special_inode_operations;
5381  
5382  /* symlink.c */
5383 +extern struct inode_operations ext2_symlink_inode_operations;
5384  extern struct inode_operations ext2_fast_symlink_inode_operations;
5385  
5386  #endif /* __KERNEL__ */
5387 Index: linux-2.4.19-pre1/include/linux/ext2_xattr.h
5388 ===================================================================
5389 --- linux-2.4.19-pre1.orig/include/linux/ext2_xattr.h   2003-01-30 13:24:37.000000000 +0300
5390 +++ linux-2.4.19-pre1/include/linux/ext2_xattr.h        2004-01-14 01:18:01.000000000 +0300
5391 @@ -0,0 +1,157 @@
5392 +/*
5393 +  File: linux/ext2_xattr.h
5394 +
5395 +  On-disk format of extended attributes for the ext2 filesystem.
5396 +
5397 +  (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
5398 +*/
5399 +
5400 +#include <linux/config.h>
5401 +#include <linux/init.h>
5402 +#include <linux/xattr.h>
5403 +
5404 +/* Magic value in attribute blocks */
5405 +#define EXT2_XATTR_MAGIC               0xEA020000
5406 +
5407 +/* Maximum number of references to one attribute block */
5408 +#define EXT2_XATTR_REFCOUNT_MAX                1024
5409 +
5410 +/* Name indexes */
5411 +#define EXT2_XATTR_INDEX_MAX                   10
5412 +#define EXT2_XATTR_INDEX_USER                  1
5413 +#define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS      2
5414 +#define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT     3
5415 +
5416 +struct ext2_xattr_header {
5417 +       __u32   h_magic;        /* magic number for identification */
5418 +       __u32   h_refcount;     /* reference count */
5419 +       __u32   h_blocks;       /* number of disk blocks used */
5420 +       __u32   h_hash;         /* hash value of all attributes */
5421 +       __u32   h_reserved[4];  /* zero right now */
5422 +};
5423 +
5424 +struct ext2_xattr_entry {
5425 +       __u8    e_name_len;     /* length of name */
5426 +       __u8    e_name_index;   /* attribute name index */
5427 +       __u16   e_value_offs;   /* offset in disk block of value */
5428 +       __u32   e_value_block;  /* disk block attribute is stored on (n/i) */
5429 +       __u32   e_value_size;   /* size of attribute value */
5430 +       __u32   e_hash;         /* hash value of name and value */
5431 +       char    e_name[0];      /* attribute name */
5432 +};
5433 +
5434 +#define EXT2_XATTR_PAD_BITS            2
5435 +#define EXT2_XATTR_PAD         (1<<EXT2_XATTR_PAD_BITS)
5436 +#define EXT2_XATTR_ROUND               (EXT2_XATTR_PAD-1)
5437 +#define EXT2_XATTR_LEN(name_len) \
5438 +       (((name_len) + EXT2_XATTR_ROUND + \
5439 +       sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND)
5440 +#define EXT2_XATTR_NEXT(entry) \
5441 +       ( (struct ext2_xattr_entry *)( \
5442 +         (char *)(entry) + EXT2_XATTR_LEN((entry)->e_name_len)) )
5443 +#define EXT2_XATTR_SIZE(size) \
5444 +       (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
5445 +
5446 +#ifdef __KERNEL__
5447 +
5448 +# ifdef CONFIG_EXT2_FS_XATTR
5449 +
5450 +struct ext2_xattr_handler {
5451 +       char *prefix;
5452 +       size_t (*list)(char *list, struct inode *inode, const char *name,
5453 +                      int name_len);
5454 +       int (*get)(struct inode *inode, const char *name, void *buffer,
5455 +                  size_t size);
5456 +       int (*set)(struct inode *inode, const char *name, const void *buffer,
5457 +                  size_t size, int flags);
5458 +};
5459 +
5460 +extern int ext2_xattr_register(int, struct ext2_xattr_handler *);
5461 +extern void ext2_xattr_unregister(int, struct ext2_xattr_handler *);
5462 +
5463 +extern int ext2_setxattr(struct dentry *, const char *, const void *, size_t, int);
5464 +extern ssize_t ext2_getxattr(struct dentry *, const char *, void *, size_t);
5465 +extern ssize_t ext2_listxattr(struct dentry *, char *, size_t);
5466 +extern int ext2_removexattr(struct dentry *, const char *);
5467 +
5468 +extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t);
5469 +extern int ext2_xattr_list(struct inode *, char *, size_t);
5470 +extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
5471 +
5472 +extern void ext2_xattr_delete_inode(struct inode *);
5473 +extern void ext2_xattr_put_super(struct super_block *);
5474 +
5475 +extern int init_ext2_xattr(void) __init;
5476 +extern void exit_ext2_xattr(void);
5477 +
5478 +# else  /* CONFIG_EXT2_FS_XATTR */
5479 +#  define ext2_setxattr                NULL
5480 +#  define ext2_getxattr                NULL
5481 +#  define ext2_listxattr       NULL
5482 +#  define ext2_removexattr     NULL
5483 +
5484 +static inline int
5485 +ext2_xattr_get(struct inode *inode, int name_index,
5486 +              const char *name, void *buffer, size_t size)
5487 +{
5488 +       return -ENOTSUP;
5489 +}
5490 +
5491 +static inline int
5492 +ext2_xattr_list(struct inode *inode, char *buffer, size_t size)
5493 +{
5494 +       return -ENOTSUP;
5495 +}
5496 +
5497 +static inline int
5498 +ext2_xattr_set(struct inode *inode, int name_index, const char *name,
5499 +              const void *value, size_t size, int flags)
5500 +{
5501 +       return -ENOTSUP;
5502 +}
5503 +
5504 +static inline void
5505 +ext2_xattr_delete_inode(struct inode *inode)
5506 +{
5507 +}
5508 +
5509 +static inline void
5510 +ext2_xattr_put_super(struct super_block *sb)
5511 +{
5512 +}
5513 +
5514 +static inline int
5515 +init_ext2_xattr(void)
5516 +{
5517 +       return 0;
5518 +}
5519 +
5520 +static inline void
5521 +exit_ext2_xattr(void)
5522 +{
5523 +}
5524 +
5525 +# endif  /* CONFIG_EXT2_FS_XATTR */
5526 +
5527 +# ifdef CONFIG_EXT2_FS_XATTR_USER
5528 +
5529 +extern int init_ext2_xattr_user(void) __init;
5530 +extern void exit_ext2_xattr_user(void);
5531 +
5532 +# else  /* CONFIG_EXT2_FS_XATTR_USER */
5533 +
5534 +static inline int
5535 +init_ext2_xattr_user(void)
5536 +{
5537 +       return 0;
5538 +}
5539 +
5540 +static inline void
5541 +exit_ext2_xattr_user(void)
5542 +{
5543 +}
5544 +
5545 +# endif  /* CONFIG_EXT2_FS_XATTR_USER */
5546 +
5547 +#endif  /* __KERNEL__ */
5548 +
5549 Index: linux-2.4.19-pre1/include/linux/ext3_fs.h
5550 ===================================================================
5551 --- linux-2.4.19-pre1.orig/include/linux/ext3_fs.h      2004-01-14 01:11:49.000000000 +0300
5552 +++ linux-2.4.19-pre1/include/linux/ext3_fs.h   2004-01-14 01:11:49.000000000 +0300
5553 @@ -63,8 +63,6 @@
5554   */
5555  #define        EXT3_BAD_INO             1      /* Bad blocks inode */
5556  #define EXT3_ROOT_INO           2      /* Root inode */
5557 -#define EXT3_ACL_IDX_INO        3      /* ACL inode */
5558 -#define EXT3_ACL_DATA_INO       4      /* ACL inode */
5559  #define EXT3_BOOT_LOADER_INO    5      /* Boot loader inode */
5560  #define EXT3_UNDEL_DIR_INO      6      /* Undelete directory inode */
5561  #define EXT3_RESIZE_INO                 7      /* Reserved group descriptors inode */
5562 @@ -94,7 +92,6 @@
5563  #else
5564  # define EXT3_BLOCK_SIZE(s)            (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size)
5565  #endif
5566 -#define EXT3_ACLE_PER_BLOCK(s)         (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry))
5567  #define        EXT3_ADDR_PER_BLOCK(s)          (EXT3_BLOCK_SIZE(s) / sizeof (__u32))
5568  #ifdef __KERNEL__
5569  # define EXT3_BLOCK_SIZE_BITS(s)       ((s)->s_blocksize_bits)
5570 @@ -129,28 +126,6 @@
5571  #endif
5572  
5573  /*
5574 - * ACL structures
5575 - */
5576 -struct ext3_acl_header /* Header of Access Control Lists */
5577 -{
5578 -       __u32   aclh_size;
5579 -       __u32   aclh_file_count;
5580 -       __u32   aclh_acle_count;
5581 -       __u32   aclh_first_acle;
5582 -};
5583 -
5584 -struct ext3_acl_entry  /* Access Control List Entry */
5585 -{
5586 -       __u32   acle_size;
5587 -       __u16   acle_perms;     /* Access permissions */
5588 -       __u16   acle_type;      /* Type of entry */
5589 -       __u16   acle_tag;       /* User or group identity */
5590 -       __u16   acle_pad1;
5591 -       __u32   acle_next;      /* Pointer on next entry for the */
5592 -                                       /* same inode or on next free entry */
5593 -};
5594 -
5595 -/*
5596   * Structure of a blocks group descriptor
5597   */
5598  struct ext3_group_desc
5599 @@ -344,6 +319,7 @@
5600    #define EXT3_MOUNT_WRITEBACK_DATA    0x0C00  /* No data ordering */
5601  #define EXT3_MOUNT_UPDATE_JOURNAL      0x1000  /* Update the journal format */
5602  #define EXT3_MOUNT_NO_UID32            0x2000  /* Disable 32-bit UIDs */
5603 +#define EXT3_MOUNT_XATTR_USER          0x4000  /* Extended user attributes */
5604  
5605  /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
5606  #ifndef _LINUX_EXT2_FS_H
5607 @@ -520,7 +496,7 @@
5608  #define EXT3_FEATURE_INCOMPAT_RECOVER          0x0004 /* Needs recovery */
5609  #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV      0x0008 /* Journal device */
5610  
5611 -#define EXT3_FEATURE_COMPAT_SUPP       0
5612 +#define EXT3_FEATURE_COMPAT_SUPP       EXT2_FEATURE_COMPAT_EXT_ATTR
5613  #define EXT3_FEATURE_INCOMPAT_SUPP     (EXT3_FEATURE_INCOMPAT_FILETYPE| \
5614                                          EXT3_FEATURE_INCOMPAT_RECOVER)
5615  #define EXT3_FEATURE_RO_COMPAT_SUPP    (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
5616 @@ -703,6 +679,7 @@
5617  extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
5618  
5619  /* inode.c */
5620 +extern int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
5621  extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
5622  extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
5623  
5624 @@ -771,8 +748,10 @@
5625  
5626  /* namei.c */
5627  extern struct inode_operations ext3_dir_inode_operations;
5628 +extern struct inode_operations ext3_special_inode_operations;
5629  
5630  /* symlink.c */
5631 +extern struct inode_operations ext3_symlink_inode_operations;
5632  extern struct inode_operations ext3_fast_symlink_inode_operations;
5633  
5634  
5635 Index: linux-2.4.19-pre1/include/linux/ext3_jbd.h
5636 ===================================================================
5637 --- linux-2.4.19-pre1.orig/include/linux/ext3_jbd.h     2004-01-14 01:11:49.000000000 +0300
5638 +++ linux-2.4.19-pre1/include/linux/ext3_jbd.h  2004-01-14 01:18:04.000000000 +0300
5639 @@ -30,13 +30,19 @@
5640  
5641  #define EXT3_SINGLEDATA_TRANS_BLOCKS   8
5642  
5643 +/* Extended attributes may touch two data buffers, two bitmap buffers,
5644 + * and two group and summaries. */
5645 +
5646 +#define EXT3_XATTR_TRANS_BLOCKS                8
5647 +
5648  /* Define the minimum size for a transaction which modifies data.  This
5649   * needs to take into account the fact that we may end up modifying two
5650   * quota files too (one for the group, one for the user quota).  The
5651   * superblock only gets updated once, of course, so don't bother
5652   * counting that again for the quota updates. */
5653  
5654 -#define EXT3_DATA_TRANS_BLOCKS         (3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2)
5655 +#define EXT3_DATA_TRANS_BLOCKS         (3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \
5656 +                                        EXT3_XATTR_TRANS_BLOCKS - 2)
5657  
5658  extern int ext3_writepage_trans_blocks(struct inode *inode);
5659  
5660 Index: linux-2.4.19-pre1/include/linux/ext3_xattr.h
5661 ===================================================================
5662 --- linux-2.4.19-pre1.orig/include/linux/ext3_xattr.h   2003-01-30 13:24:37.000000000 +0300
5663 +++ linux-2.4.19-pre1/include/linux/ext3_xattr.h        2004-01-14 01:11:49.000000000 +0300
5664 @@ -0,0 +1,157 @@
5665 +/*
5666 +  File: linux/ext3_xattr.h
5667 +
5668 +  On-disk format of extended attributes for the ext3 filesystem.
5669 +
5670 +  (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
5671 +*/
5672 +
5673 +#include <linux/config.h>
5674 +#include <linux/init.h>
5675 +#include <linux/xattr.h>
5676 +
5677 +/* Magic value in attribute blocks */
5678 +#define EXT3_XATTR_MAGIC               0xEA020000
5679 +
5680 +/* Maximum number of references to one attribute block */
5681 +#define EXT3_XATTR_REFCOUNT_MAX                1024
5682 +
5683 +/* Name indexes */
5684 +#define EXT3_XATTR_INDEX_MAX                   10
5685 +#define EXT3_XATTR_INDEX_USER                  1
5686 +#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS      2
5687 +#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT     3
5688 +
5689 +struct ext3_xattr_header {
5690 +       __u32   h_magic;        /* magic number for identification */
5691 +       __u32   h_refcount;     /* reference count */
5692 +       __u32   h_blocks;       /* number of disk blocks used */
5693 +       __u32   h_hash;         /* hash value of all attributes */
5694 +       __u32   h_reserved[4];  /* zero right now */
5695 +};
5696 +
5697 +struct ext3_xattr_entry {
5698 +       __u8    e_name_len;     /* length of name */
5699 +       __u8    e_name_index;   /* attribute name index */
5700 +       __u16   e_value_offs;   /* offset in disk block of value */
5701 +       __u32   e_value_block;  /* disk block attribute is stored on (n/i) */
5702 +       __u32   e_value_size;   /* size of attribute value */
5703 +       __u32   e_hash;         /* hash value of name and value */
5704 +       char    e_name[0];      /* attribute name */
5705 +};
5706 +
5707 +#define EXT3_XATTR_PAD_BITS            2
5708 +#define EXT3_XATTR_PAD         (1<<EXT3_XATTR_PAD_BITS)
5709 +#define EXT3_XATTR_ROUND               (EXT3_XATTR_PAD-1)
5710 +#define EXT3_XATTR_LEN(name_len) \
5711 +       (((name_len) + EXT3_XATTR_ROUND + \
5712 +       sizeof(struct ext3_xattr_entry)) & ~EXT3_XATTR_ROUND)
5713 +#define EXT3_XATTR_NEXT(entry) \
5714 +       ( (struct ext3_xattr_entry *)( \
5715 +         (char *)(entry) + EXT3_XATTR_LEN((entry)->e_name_len)) )
5716 +#define EXT3_XATTR_SIZE(size) \
5717 +       (((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND)
5718 +
5719 +#ifdef __KERNEL__
5720 +
5721 +# ifdef CONFIG_EXT3_FS_XATTR
5722 +
5723 +struct ext3_xattr_handler {
5724 +       char *prefix;
5725 +       size_t (*list)(char *list, struct inode *inode, const char *name,
5726 +                      int name_len);
5727 +       int (*get)(struct inode *inode, const char *name, void *buffer,
5728 +                  size_t size);
5729 +       int (*set)(struct inode *inode, const char *name, const void *buffer,
5730 +                  size_t size, int flags);
5731 +};
5732 +
5733 +extern int ext3_xattr_register(int, struct ext3_xattr_handler *);
5734 +extern void ext3_xattr_unregister(int, struct ext3_xattr_handler *);
5735 +
5736 +extern int ext3_setxattr(struct dentry *, const char *, const void *, size_t, int);
5737 +extern ssize_t ext3_getxattr(struct dentry *, const char *, void *, size_t);
5738 +extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
5739 +extern int ext3_removexattr(struct dentry *, const char *);
5740 +
5741 +extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t);
5742 +extern int ext3_xattr_list(struct inode *, char *, size_t);
5743 +extern int ext3_xattr_set(handle_t *handle, struct inode *, int, const char *, const void *, size_t, int);
5744 +
5745 +extern void ext3_xattr_delete_inode(handle_t *, struct inode *);
5746 +extern void ext3_xattr_put_super(struct super_block *);
5747 +
5748 +extern int init_ext3_xattr(void) __init;
5749 +extern void exit_ext3_xattr(void);
5750 +
5751 +# else  /* CONFIG_EXT3_FS_XATTR */
5752 +#  define ext3_setxattr                NULL
5753 +#  define ext3_getxattr                NULL
5754 +#  define ext3_listxattr       NULL
5755 +#  define ext3_removexattr     NULL
5756 +
5757 +static inline int
5758 +ext3_xattr_get(struct inode *inode, int name_index, const char *name,
5759 +              void *buffer, size_t size)
5760 +{
5761 +       return -ENOTSUP;
5762 +}
5763 +
5764 +static inline int
5765 +ext3_xattr_list(struct inode *inode, void *buffer, size_t size)
5766 +{
5767 +       return -ENOTSUP;
5768 +}
5769 +
5770 +static inline int
5771 +ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
5772 +              const char *name, const void *value, size_t size, int flags)
5773 +{
5774 +       return -ENOTSUP;
5775 +}
5776 +
5777 +static inline void
5778 +ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
5779 +{
5780 +}
5781 +
5782 +static inline void
5783 +ext3_xattr_put_super(struct super_block *sb)
5784 +{
5785 +}
5786 +
5787 +static inline int
5788 +init_ext3_xattr(void)
5789 +{
5790 +       return 0;
5791 +}
5792 +
5793 +static inline void
5794 +exit_ext3_xattr(void)
5795 +{
5796 +}
5797 +
5798 +# endif  /* CONFIG_EXT3_FS_XATTR */
5799 +
5800 +# ifdef CONFIG_EXT3_FS_XATTR_USER
5801 +
5802 +extern int init_ext3_xattr_user(void) __init;
5803 +extern void exit_ext3_xattr_user(void);
5804 +
5805 +# else  /* CONFIG_EXT3_FS_XATTR_USER */
5806 +
5807 +static inline int
5808 +init_ext3_xattr_user(void)
5809 +{
5810 +       return 0;
5811 +}
5812 +
5813 +static inline void
5814 +exit_ext3_xattr_user(void)
5815 +{
5816 +}
5817 +
5818 +#endif  /* CONFIG_EXT3_FS_XATTR_USER */
5819 +
5820 +#endif  /* __KERNEL__ */
5821 +
5822 Index: linux-2.4.19-pre1/include/linux/fs.h
5823 ===================================================================
5824 --- linux-2.4.19-pre1.orig/include/linux/fs.h   2004-01-14 01:11:48.000000000 +0300
5825 +++ linux-2.4.19-pre1/include/linux/fs.h        2004-01-14 01:11:49.000000000 +0300
5826 @@ -872,6 +872,10 @@
5827         int (*setattr) (struct dentry *, struct iattr *);
5828         int (*setattr_raw) (struct inode *, struct iattr *);
5829         int (*getattr) (struct dentry *, struct iattr *);
5830 +       int (*setxattr) (struct dentry *, const char *, const void *, size_t, int);
5831 +       ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
5832 +       ssize_t (*listxattr) (struct dentry *, char *, size_t);
5833 +       int (*removexattr) (struct dentry *, const char *);
5834  };
5835  
5836  struct seq_file;
5837 Index: linux-2.4.19-pre1/include/linux/mbcache.h
5838 ===================================================================
5839 --- linux-2.4.19-pre1.orig/include/linux/mbcache.h      2003-01-30 13:24:37.000000000 +0300
5840 +++ linux-2.4.19-pre1/include/linux/mbcache.h   2004-01-14 01:11:49.000000000 +0300
5841 @@ -0,0 +1,69 @@
5842 +/*
5843 +  File: linux/mbcache.h
5844 +
5845 +  (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
5846 +*/
5847 +
5848 +/* Hardwire the number of additional indexes */
5849 +#define MB_CACHE_INDEXES_COUNT 1
5850 +
5851 +struct mb_cache_entry;
5852 +
5853 +struct mb_cache_op {
5854 +       int (*free)(struct mb_cache_entry *, int);
5855 +};
5856 +
5857 +struct mb_cache {
5858 +       struct list_head                c_cache_list;
5859 +       const char                      *c_name;
5860 +       struct mb_cache_op              c_op;
5861 +       atomic_t                        c_entry_count;
5862 +       int                             c_bucket_count;
5863 +#ifndef MB_CACHE_INDEXES_COUNT
5864 +       int                             c_indexes_count;
5865 +#endif
5866 +       kmem_cache_t                    *c_entry_cache;
5867 +       struct list_head                *c_block_hash;
5868 +       struct list_head                *c_indexes_hash[0];
5869 +};
5870 +
5871 +struct mb_cache_entry_index {
5872 +       struct list_head                o_list;
5873 +       unsigned int                    o_key;
5874 +};
5875 +
5876 +struct mb_cache_entry {
5877 +       struct list_head                e_lru_list;
5878 +       struct mb_cache                 *e_cache;
5879 +       atomic_t                        e_used;
5880 +       kdev_t                          e_dev;
5881 +       unsigned long                   e_block;
5882 +       struct list_head                e_block_list;
5883 +       struct mb_cache_entry_index     e_indexes[0];
5884 +};
5885 +
5886 +/* Functions on caches */
5887 +
5888 +struct mb_cache * mb_cache_create(const char *, struct mb_cache_op *, size_t,
5889 +                                 int, int);
5890 +void mb_cache_shrink(struct mb_cache *, kdev_t);
5891 +void mb_cache_destroy(struct mb_cache *);
5892 +
5893 +/* Functions on cache entries */
5894 +
5895 +struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *);
5896 +int mb_cache_entry_insert(struct mb_cache_entry *, kdev_t, unsigned long,
5897 +                         unsigned int[]);
5898 +void mb_cache_entry_rehash(struct mb_cache_entry *, unsigned int[]);
5899 +void mb_cache_entry_release(struct mb_cache_entry *);
5900 +void mb_cache_entry_takeout(struct mb_cache_entry *);
5901 +void mb_cache_entry_free(struct mb_cache_entry *);
5902 +struct mb_cache_entry *mb_cache_entry_dup(struct mb_cache_entry *);
5903 +struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *, kdev_t,
5904 +                                         unsigned long);
5905 +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0)
5906 +struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, int,
5907 +                                                kdev_t, unsigned int);
5908 +struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache_entry *, int,
5909 +                                               kdev_t, unsigned int);
5910 +#endif
5911 Index: linux-2.4.19-pre1/include/linux/xattr.h
5912 ===================================================================
5913 --- linux-2.4.19-pre1.orig/include/linux/xattr.h        2003-01-30 13:24:37.000000000 +0300
5914 +++ linux-2.4.19-pre1/include/linux/xattr.h     2004-01-14 01:11:49.000000000 +0300
5915 @@ -0,0 +1,15 @@
5916 +/*
5917 +  File: linux/xattr.h
5918 +
5919 +  Extended attributes handling.
5920 +
5921 +  Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
5922 +  Copyright (c) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
5923 +*/
5924 +#ifndef _LINUX_XATTR_H
5925 +#define _LINUX_XATTR_H
5926 +
5927 +#define XATTR_CREATE   0x1     /* set the value, fail if attr already exists */
5928 +#define XATTR_REPLACE  0x2     /* set the value, fail if attr does not exist */
5929 +
5930 +#endif /* _LINUX_XATTR_H */
5931 Index: linux-2.4.19-pre1/include/linux/kernel.h
5932 ===================================================================
5933 --- linux-2.4.19-pre1.orig/include/linux/kernel.h       2004-01-14 01:10:37.000000000 +0300
5934 +++ linux-2.4.19-pre1/include/linux/kernel.h    2004-01-14 01:16:51.000000000 +0300
5935 @@ -11,6 +11,7 @@
5936  #include <linux/linkage.h>
5937  #include <linux/stddef.h>
5938  #include <linux/types.h>
5939 +#include <linux/compiler.h>
5940  
5941  /* Optimization barrier */
5942  /* The "volatile" is due to gcc bugs */
5943 Index: linux-2.4.19-pre1/include/linux/limits.h
5944 ===================================================================
5945 --- linux-2.4.19-pre1.orig/include/linux/limits.h       2004-01-14 01:10:37.000000000 +0300
5946 +++ linux-2.4.19-pre1/include/linux/limits.h    2004-01-14 01:22:08.000000000 +0300
5947 @@ -13,6 +13,9 @@
5948  #define NAME_MAX         255   /* # chars in a file name */
5949  #define PATH_MAX        4096   /* # chars in a path name including nul */
5950  #define PIPE_BUF        4096   /* # bytes in atomic write to a pipe */
5951 +#define XATTR_NAME_MAX   255   /* # chars in an extended attribute name */
5952 +#define XATTR_SIZE_MAX 65536   /* size of an extended attribute value (64k) */
5953 +#define XATTR_LIST_MAX 65536   /* size of extended attribute namelist (64k) */
5954  
5955  #define RTSIG_MAX        32
5956  
5957 Index: linux-2.4.19-pre1/kernel/ksyms.c
5958 ===================================================================
5959 --- linux-2.4.19-pre1.orig/kernel/ksyms.c       2004-01-14 01:11:48.000000000 +0300
5960 +++ linux-2.4.19-pre1/kernel/ksyms.c    2004-01-14 01:11:49.000000000 +0300
5961 @@ -11,6 +11,7 @@
5962  
5963  #include <linux/config.h>
5964  #include <linux/slab.h>
5965 +#include <linux/cache_def.h>
5966  #include <linux/module.h>
5967  #include <linux/blkdev.h>
5968  #include <linux/cdrom.h>
5969 @@ -88,6 +89,7 @@
5970  EXPORT_SYMBOL(exit_files);
5971  EXPORT_SYMBOL(exit_fs);
5972  EXPORT_SYMBOL(exit_sighand);
5973 +EXPORT_SYMBOL(copy_fs_struct);
5974  
5975  /* internal kernel memory management */
5976  EXPORT_SYMBOL(_alloc_pages);
5977 @@ -104,6 +106,8 @@
5978  EXPORT_SYMBOL(kmem_cache_shrink);
5979  EXPORT_SYMBOL(kmem_cache_alloc);
5980  EXPORT_SYMBOL(kmem_cache_free);
5981 +EXPORT_SYMBOL(register_cache);
5982 +EXPORT_SYMBOL(unregister_cache);
5983  EXPORT_SYMBOL(kmalloc);
5984  EXPORT_SYMBOL(kfree);
5985  EXPORT_SYMBOL(vfree);
5986 Index: linux-2.4.19-pre1/mm/vmscan.c
5987 ===================================================================
5988 --- linux-2.4.19-pre1.orig/mm/vmscan.c  2004-01-14 01:10:37.000000000 +0300
5989 +++ linux-2.4.19-pre1/mm/vmscan.c       2004-01-14 01:11:49.000000000 +0300
5990 @@ -15,6 +15,7 @@
5991  #include <linux/kernel_stat.h>
5992  #include <linux/swap.h>
5993  #include <linux/swapctl.h>
5994 +#include <linux/cache_def.h>
5995  #include <linux/smp_lock.h>
5996  #include <linux/pagemap.h>
5997  #include <linux/init.h>
5998 @@ -32,6 +33,39 @@
5999   */
6000  #define DEF_PRIORITY (6)
6001  
6002 +static DECLARE_MUTEX(other_caches_sem);
6003 +static LIST_HEAD(cache_definitions);
6004 +
6005 +void register_cache(struct cache_definition *cache)
6006 +{
6007 +       down(&other_caches_sem);
6008 +       list_add(&cache->link, &cache_definitions);
6009 +       up(&other_caches_sem);
6010 +}
6011 +
6012 +void unregister_cache(struct cache_definition *cache)
6013 +{
6014 +       down(&other_caches_sem);
6015 +       list_del(&cache->link);
6016 +       up(&other_caches_sem);
6017 +}
6018 +
6019 +static void shrink_other_caches(unsigned int priority, int gfp_mask)
6020 +{
6021 +       struct list_head *p;
6022 +
6023 +       if (down_trylock(&other_caches_sem))
6024 +               return;
6025 +
6026 +       list_for_each_prev(p, &cache_definitions) {
6027 +               struct cache_definition *cache =
6028 +                       list_entry(p, struct cache_definition, link);
6029 +
6030 +               cache->shrink(priority, gfp_mask);
6031 +       }
6032 +       up(&other_caches_sem);
6033 +}
6034 +
6035  /*
6036   * The swap-out function returns 1 if it successfully
6037   * scanned all the pages it was asked to (`count').
6038 @@ -578,6 +612,7 @@
6039  
6040         shrink_dcache_memory(priority, gfp_mask);
6041         shrink_icache_memory(priority, gfp_mask);
6042 +       shrink_other_caches(priority, gfp_mask);
6043  #ifdef CONFIG_QUOTA
6044         shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
6045  #endif