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