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