Whamcloud - gitweb
- extents patch updated from b1_4:
[fs/lustre-release.git] / lustre / kernel_patches / patches / ext3-ea-in-inode-2.4.22-rh.patch
1  fs/ext3/ialloc.c          |    6 
2  fs/ext3/inode.c           |   12 
3  fs/ext3/super.c           |    6 
4  fs/ext3/xattr.c           |  597 +++++++++++++++++++++++++++++++++++++++++++++-
5  include/linux/ext3_fs.h   |    2 
6  include/linux/ext3_fs_i.h |    3 
7  6 files changed, 615 insertions(+), 11 deletions(-)
8
9 Index: linux-2.4.24/fs/ext3/ialloc.c
10 ===================================================================
11 --- linux-2.4.24.orig/fs/ext3/ialloc.c  2004-07-13 11:07:17.000000000 +0400
12 +++ linux-2.4.24/fs/ext3/ialloc.c       2004-07-14 18:04:43.000000000 +0400
13 @@ -576,6 +576,13 @@
14         insert_inode_hash(inode);
15         inode->i_generation = sb->u.ext3_sb.s_next_generation++;
16  
17 +       if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
18 +               inode->u.ext3_i.i_extra_isize = sizeof(__u16)   /* i_extra_isize */
19 +                               + sizeof(__u16);        /* i_pad1 */
20 +               inode->u.ext3_i.i_flags |= EXT3_EXTRA_ISIZE;
21 +       } else
22 +               inode->u.ext3_i.i_extra_isize = 0;
23 +
24         inode->u.ext3_i.i_state = EXT3_STATE_NEW;
25         err = ext3_get_inode_loc_new(inode, &iloc, 1);
26         if (err) goto fail;
27 Index: linux-2.4.24/fs/ext3/inode.c
28 ===================================================================
29 --- linux-2.4.24.orig/fs/ext3/inode.c   2004-07-13 11:07:18.000000000 +0400
30 +++ linux-2.4.24/fs/ext3/inode.c        2004-07-14 18:11:39.000000000 +0400
31 @@ -2225,6 +2225,23 @@
32                 inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
33         INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
34  
35 +       inode->u.ext3_i.i_extra_isize = 0;
36 +       if (inode->u.ext3_i.i_flags & EXT3_EXTRA_ISIZE) {
37 +               BUG_ON(EXT3_INODE_SIZE(inode->i_sb) <= EXT3_GOOD_OLD_INODE_SIZE);
38 +               inode->u.ext3_i.i_extra_isize =
39 +                       le16_to_cpu(raw_inode->i_extra_isize);
40 +       } else if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
41 +               /* this is dirty hack for already formatted filesystems:
42 +                * inodes with inum <= 11 are created by mke2fs that doesn't
43 +                * initialize extra space and inodes with larger inum are
44 +                * created by ext3 itself that initializes extra space -bzzz */
45 +               if (inode->i_ino > 11)
46 +                       inode->u.ext3_i.i_extra_isize =
47 +                               le16_to_cpu(raw_inode->i_extra_isize);
48 +       }
49 +       block = EXT3_INODE_SIZE(inode->i_sb) - EXT3_GOOD_OLD_INODE_SIZE;
50 +       BUG_ON(inode->u.ext3_i.i_extra_isize > block);
51 +
52         if (S_ISREG(inode->i_mode)) {
53                 inode->i_op = &ext3_file_inode_operations;
54                 inode->i_fop = &ext3_file_operations;
55 @@ -2273,6 +2290,8 @@
56                 if (err)
57                         goto out_brelse;
58         }
59 +       if (EXT3_I(inode)->i_state & EXT3_STATE_NEW)
60 +               memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb));
61         raw_inode->i_mode = cpu_to_le16(inode->i_mode);
62         if(!(test_opt(inode->i_sb, NO_UID32))) {
63                 raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
64 @@ -2356,6 +2375,10 @@
65         else for (block = 0; block < EXT3_N_BLOCKS; block++)
66                 raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
67  
68 +       if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
69 +               raw_inode->i_extra_isize =
70 +                       cpu_to_le16(EXT3_I(inode)->i_extra_isize);
71 +
72         BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
73         rc = ext3_journal_dirty_metadata(handle, bh);
74         if (!err)
75 Index: linux-2.4.24/fs/ext3/super.c
76 ===================================================================
77 --- linux-2.4.24.orig/fs/ext3/super.c   2004-07-13 11:07:19.000000000 +0400
78 +++ linux-2.4.24/fs/ext3/super.c        2004-07-14 18:00:14.000000000 +0400
79 @@ -1203,8 +1203,10 @@
80         } else {
81                 sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
82                 sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
83 -               if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
84 -                       printk (KERN_ERR
85 +               if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
86 +                               (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
87 +                               (sbi->s_inode_size > blocksize)) {
88 +                       printk (KERN_ERR
89                                 "EXT3-fs: unsupported inode size: %d\n",
90                                 sbi->s_inode_size);
91                         goto failed_mount;
92 Index: linux-2.4.24/fs/ext3/xattr.c
93 ===================================================================
94 --- linux-2.4.24.orig/fs/ext3/xattr.c   2004-07-13 11:07:16.000000000 +0400
95 +++ linux-2.4.24/fs/ext3/xattr.c        2004-07-14 18:00:14.000000000 +0400
96 @@ -100,6 +100,9 @@
97  static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
98                            struct ext3_xattr_header *);
99  
100 +int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
101 +                       const void *, size_t, int);
102 +
103  #ifdef CONFIG_EXT3_FS_XATTR_SHARING
104  
105  static int ext3_xattr_cache_insert(struct buffer_head *);
106 @@ -348,17 +351,12 @@
107  }
108  
109  /*
110 - * ext3_xattr_get()
111 - *
112 - * Copy an extended attribute into the buffer
113 - * provided, or compute the buffer size required.
114 - * Buffer is NULL to compute the size of the buffer required.
115 + * ext3_xattr_block_get()
116   *
117 - * Returns a negative error number on failure, or the number of bytes
118 - * used / required on success.
119 + * routine looks for attribute in EA block and returns it's value and size
120   */
121  int
122 -ext3_xattr_get(struct inode *inode, int name_index, const char *name,
123 +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
124                void *buffer, size_t buffer_size)
125  {
126         struct buffer_head *bh = NULL;
127 @@ -447,6 +445,94 @@
128  }
129  
130  /*
131 + * ext3_xattr_ibode_get()
132 + *
133 + * routine looks for attribute in inode body and returns it's value and size
134 + */
135 +int
136 +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
137 +              void *buffer, size_t buffer_size)
138 +{
139 +       int size, name_len = strlen(name), storage_size;
140 +       struct ext3_xattr_entry *last;
141 +       struct ext3_inode *raw_inode;
142 +       struct ext3_iloc iloc;
143 +       char *start, *end;
144 +       int ret = -ENOENT;
145 +       
146 +       if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
147 +               return -ENOENT;
148 +
149 +       ret = ext3_get_inode_loc(inode, &iloc);
150 +       if (ret)
151 +               return ret;
152 +       raw_inode = iloc.raw_inode;
153 +
154 +       storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
155 +                               EXT3_GOOD_OLD_INODE_SIZE -
156 +                               EXT3_I(inode)->i_extra_isize -
157 +                               sizeof(__u32);
158 +       start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
159 +                       EXT3_I(inode)->i_extra_isize;
160 +       if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
161 +               brelse(iloc.bh);
162 +               return -ENOENT;
163 +       }
164 +       start += sizeof(__u32);
165 +       end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
166 +
167 +       last = (struct ext3_xattr_entry *) start;
168 +       while (!IS_LAST_ENTRY(last)) {
169 +               struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
170 +               if (le32_to_cpu(last->e_value_size) > storage_size ||
171 +                               (char *) next >= end) {
172 +                       ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
173 +                               "inode %ld", inode->i_ino);
174 +                       brelse(iloc.bh);
175 +                       return -EIO;
176 +               }
177 +               if (name_index == last->e_name_index &&
178 +                   name_len == last->e_name_len &&
179 +                   !memcmp(name, last->e_name, name_len))
180 +                       goto found;
181 +               last = next;
182 +       }
183 +
184 +       /* can't find EA */
185 +       brelse(iloc.bh);
186 +       return -ENOENT;
187 +       
188 +found:
189 +       size = le32_to_cpu(last->e_value_size);
190 +       if (buffer) {
191 +               ret = -ERANGE;
192 +               if (buffer_size >= size) {
193 +                       memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
194 +                       size);
195 +                       ret = size;
196 +               }
197 +       } else
198 +               ret = size;
199 +       brelse(iloc.bh);
200 +       return ret;
201 +}
202 +
203 +int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
204 +                       void *buffer, size_t buffer_size)
205 +{
206 +       int err;
207 +
208 +       /* try to find attribute in inode body */
209 +       err = ext3_xattr_ibody_get(inode, name_index, name,
210 +                                       buffer, buffer_size);
211 +       if (err < 0)
212 +               /* search was unsuccessful, try to find EA in dedicated block */
213 +               err = ext3_xattr_block_get(inode, name_index, name,
214 +                               buffer, buffer_size);
215 +       return err;
216 +}
217 +
218 +/*
219   * ext3_xattr_list()
220   *
221   * Copy a list of attribute names into the buffer
222 @@ -457,7 +543,7 @@
223   * used / required on success.
224   */
225  int
226 -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
227 +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
228  {
229         struct buffer_head *bh = NULL;
230         struct ext3_xattr_entry *entry;
231 @@ -530,6 +616,131 @@
232         return error;
233  }
234  
235 +/* ext3_xattr_ibody_list()
236 + *
237 + * generate list of attributes stored in inode body
238 + */
239 +int
240 +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
241 +{
242 +       struct ext3_xattr_entry *last;
243 +       struct ext3_inode *raw_inode;
244 +       char *start, *end, *buf;
245 +       struct ext3_iloc iloc;
246 +       int storage_size;
247 +       int ret;
248 +       int size = 0;
249 +       
250 +       if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
251 +               return 0;
252 +
253 +       ret = ext3_get_inode_loc(inode, &iloc);
254 +       if (ret)
255 +               return ret;
256 +       raw_inode = iloc.raw_inode;
257 +
258 +       storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
259 +                               EXT3_GOOD_OLD_INODE_SIZE -
260 +                               EXT3_I(inode)->i_extra_isize -
261 +                               sizeof(__u32);
262 +       start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
263 +                       EXT3_I(inode)->i_extra_isize;
264 +       if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
265 +               brelse(iloc.bh);
266 +               return 0;
267 +       }
268 +       start += sizeof(__u32);
269 +       end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
270 +
271 +       last = (struct ext3_xattr_entry *) start;
272 +       while (!IS_LAST_ENTRY(last)) {
273 +               struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
274 +               struct ext3_xattr_handler *handler;
275 +               if (le32_to_cpu(last->e_value_size) > storage_size ||
276 +                               (char *) next >= end) {
277 +                       ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
278 +                               "inode %ld", inode->i_ino);
279 +                       brelse(iloc.bh);
280 +                       return -EIO;
281 +               }
282 +               handler = ext3_xattr_handler(last->e_name_index);
283 +               if (handler)
284 +                       size += handler->list(NULL, inode, last->e_name,
285 +                                             last->e_name_len);
286 +               last = next;
287 +       }
288 +
289 +       if (!buffer) {
290 +               ret = size;
291 +               goto cleanup;
292 +       } else {
293 +               ret = -ERANGE;
294 +               if (size > buffer_size)
295 +                       goto cleanup;
296 +       }
297 +
298 +       last = (struct ext3_xattr_entry *) start;
299 +       buf = buffer;
300 +       while (!IS_LAST_ENTRY(last)) {
301 +               struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
302 +               struct ext3_xattr_handler *handler;
303 +               handler = ext3_xattr_handler(last->e_name_index);
304 +               if (handler)
305 +                       buf += handler->list(buf, inode, last->e_name,
306 +                                             last->e_name_len);
307 +               last = next;
308 +       }
309 +       ret = size;
310 +cleanup:
311 +       brelse(iloc.bh);
312 +       return ret;
313 +}
314 +
315 +/*
316 + * ext3_xattr_list()
317 + *
318 + * Copy a list of attribute names into the buffer
319 + * provided, or compute the buffer size required.
320 + * Buffer is NULL to compute the size of the buffer required.
321 + *
322 + * Returns a negative error number on failure, or the number of bytes
323 + * used / required on success.
324 + */
325 +int
326 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
327 +{
328 +       int error;
329 +       int size = buffer_size;
330 +
331 +       /* get list of attributes stored in inode body */
332 +       error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
333 +       if (error < 0) {
334 +               /* some error occured while collecting
335 +                * attributes in inode body */
336 +               size = 0;
337 +               goto cleanup;
338 +       }
339 +       size = error;
340 +
341 +       /* get list of attributes stored in dedicated block */
342 +       if (buffer) {
343 +               buffer_size -= error;
344 +               if (buffer_size <= 0) {
345 +                       buffer = NULL;
346 +                       buffer_size = 0;
347 +               } else
348 +                       buffer += error;
349 +       }
350 +
351 +       error = ext3_xattr_block_list(inode, buffer, buffer_size);
352 +       if (error < 0)
353 +               /* listing was successful, so we return len */
354 +               size = 0;
355 +
356 +cleanup:
357 +       return error + size;
358 +}
359 +
360  /*
361   * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
362   * not set, set it.
363 @@ -553,6 +764,279 @@
364  }
365  
366  /*
367 + * ext3_xattr_ibody_find()
368 + *
369 + * search attribute and calculate free space in inode body
370 + * NOTE: free space includes space our attribute hold
371 + */
372 +int
373 +ext3_xattr_ibody_find(struct inode *inode, int name_index,
374 +               const char *name, struct ext3_xattr_entry *rentry, int *free)
375 +{
376 +       struct ext3_xattr_entry *last;
377 +       struct ext3_inode *raw_inode;
378 +       int name_len = strlen(name);
379 +       int err, storage_size;
380 +       struct ext3_iloc iloc;
381 +       char *start, *end;
382 +       int ret = -ENOENT;
383 +       
384 +       if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
385 +               return ret;
386 +
387 +       err = ext3_get_inode_loc(inode, &iloc);
388 +       if (err)
389 +               return -EIO;
390 +       raw_inode = iloc.raw_inode;
391 +
392 +       storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
393 +                               EXT3_GOOD_OLD_INODE_SIZE -
394 +                               EXT3_I(inode)->i_extra_isize -
395 +                               sizeof(__u32);
396 +       *free = storage_size - sizeof(__u32);
397 +       start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
398 +                       EXT3_I(inode)->i_extra_isize;
399 +       if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
400 +               brelse(iloc.bh);
401 +               return -ENOENT;
402 +       }
403 +       start += sizeof(__u32);
404 +       end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
405 +
406 +       last = (struct ext3_xattr_entry *) start;
407 +       while (!IS_LAST_ENTRY(last)) {
408 +               struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
409 +               if (le32_to_cpu(last->e_value_size) > storage_size ||
410 +                               (char *) next >= end) {
411 +                       ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
412 +                               "inode %ld", inode->i_ino);
413 +                       brelse(iloc.bh);
414 +                       return -EIO;
415 +               }
416 +
417 +               if (name_index == last->e_name_index &&
418 +                   name_len == last->e_name_len &&
419 +                   !memcmp(name, last->e_name, name_len)) {
420 +                       memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
421 +                       ret = 0;
422 +               } else {
423 +                       *free -= EXT3_XATTR_LEN(last->e_name_len);
424 +                       *free -= le32_to_cpu(last->e_value_size);
425 +               }
426 +               last = next;
427 +       }
428 +       
429 +       brelse(iloc.bh);
430 +       return ret;
431 +}
432 +
433 +/*
434 + * ext3_xattr_block_find()
435 + *
436 + * search attribute and calculate free space in EA block (if it allocated)
437 + * NOTE: free space includes space our attribute hold
438 + */
439 +int
440 +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
441 +              struct ext3_xattr_entry *rentry, int *free)
442 +{
443 +       struct buffer_head *bh = NULL;
444 +       struct ext3_xattr_entry *entry;
445 +       char *end;
446 +       int name_len, error = -ENOENT;
447 +
448 +       if (!EXT3_I(inode)->i_file_acl) {
449 +               *free = inode->i_sb->s_blocksize -
450 +                       sizeof(struct ext3_xattr_header) -
451 +                       sizeof(__u32);
452 +               return -ENOENT;
453 +       }
454 +       ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
455 +       bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
456 +       if (!bh)
457 +               return -EIO;
458 +       ea_bdebug(bh, "b_count=%d, refcount=%d",
459 +               atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
460 +       end = bh->b_data + bh->b_size;
461 +       if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
462 +           HDR(bh)->h_blocks != cpu_to_le32(1)) {
463 +bad_block:     ext3_error(inode->i_sb, "ext3_xattr_get",
464 +                       "inode %ld: bad block %d", inode->i_ino,
465 +                       EXT3_I(inode)->i_file_acl);
466 +               brelse(bh);
467 +               return -EIO;
468 +       }
469 +       /* find named attribute */
470 +       name_len = strlen(name);
471 +       *free = bh->b_size - sizeof(__u32);
472 +
473 +       entry = FIRST_ENTRY(bh);
474 +       while (!IS_LAST_ENTRY(entry)) {
475 +               struct ext3_xattr_entry *next =
476 +                       EXT3_XATTR_NEXT(entry);
477 +               if ((char *)next >= end)
478 +                       goto bad_block;
479 +               if (name_index == entry->e_name_index &&
480 +                   name_len == entry->e_name_len &&
481 +                   memcmp(name, entry->e_name, name_len) == 0) {
482 +                       memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
483 +                       error = 0;
484 +               } else {
485 +                       *free -= EXT3_XATTR_LEN(entry->e_name_len);
486 +                       *free -= le32_to_cpu(entry->e_value_size);
487 +               }
488 +               entry = next;
489 +       }
490 +       brelse(bh);
491 +
492 +       return error;
493 +}
494 +
495 +/*
496 + * ext3_xattr_inode_set()
497 + *
498 + * this routine add/remove/replace attribute in inode body
499 + */
500 +int
501 +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
502 +                     const char *name, const void *value, size_t value_len,
503 +                     int flags)
504 +{
505 +       struct ext3_xattr_entry *last, *next, *here = NULL;
506 +       struct ext3_inode *raw_inode;
507 +       int name_len = strlen(name);
508 +       int esize = EXT3_XATTR_LEN(name_len);
509 +       struct buffer_head *bh;
510 +       int err, storage_size;
511 +       struct ext3_iloc iloc;
512 +       int free, min_offs;
513 +       char *start, *end;
514 +       
515 +       if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
516 +               return -ENOSPC;
517 +
518 +       err = ext3_get_inode_loc(inode, &iloc);
519 +       if (err)
520 +               return err;
521 +       raw_inode = iloc.raw_inode;
522 +       bh = iloc.bh;
523 +
524 +       storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
525 +                               EXT3_GOOD_OLD_INODE_SIZE -
526 +                               EXT3_I(inode)->i_extra_isize -
527 +                               sizeof(__u32);
528 +       start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
529 +                       EXT3_I(inode)->i_extra_isize;
530 +       if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
531 +               /* inode had no attributes before */
532 +               *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
533 +       }
534 +       start += sizeof(__u32);
535 +       end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
536 +       min_offs = storage_size;
537 +       free = storage_size - sizeof(__u32);
538 +
539 +       last = (struct ext3_xattr_entry *) start;       
540 +       while (!IS_LAST_ENTRY(last)) {
541 +               next = EXT3_XATTR_NEXT(last);
542 +               if (le32_to_cpu(last->e_value_size) > storage_size ||
543 +                               (char *) next >= end) {
544 +                       ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
545 +                               "inode %ld", inode->i_ino);
546 +                       brelse(bh);
547 +                       return -EIO;
548 +               }
549 +               
550 +               if (last->e_value_size) {
551 +                       int offs = le16_to_cpu(last->e_value_offs);
552 +                       if (offs < min_offs)
553 +                               min_offs = offs;
554 +               }
555 +               if (name_index == last->e_name_index &&
556 +                       name_len == last->e_name_len &&
557 +                       !memcmp(name, last->e_name, name_len))
558 +                       here = last;
559 +               else {
560 +                       /* we calculate all but our attribute
561 +                        * because it will be removed before changing */
562 +                       free -= EXT3_XATTR_LEN(last->e_name_len);
563 +                       free -= le32_to_cpu(last->e_value_size);
564 +               }
565 +               last = next;
566 +       }
567 +
568 +       if (value && (esize + value_len > free)) {
569 +               brelse(bh);
570 +               return -ENOSPC;
571 +       }
572 +       
573 +       err = ext3_reserve_inode_write(handle, inode, &iloc);
574 +       if (err) {
575 +               brelse(bh);     
576 +               return err;
577 +       }
578 +
579 +       if (here) {
580 +               /* time to remove old value */
581 +               struct ext3_xattr_entry *e;
582 +               int size = le32_to_cpu(here->e_value_size);
583 +               int border = le16_to_cpu(here->e_value_offs);
584 +               char *src;
585 +
586 +               /* move tail */
587 +               memmove(start + min_offs + size, start + min_offs,
588 +                               border - min_offs);
589 +
590 +               /* recalculate offsets */
591 +               e = (struct ext3_xattr_entry *) start;
592 +               while (!IS_LAST_ENTRY(e)) {
593 +                       struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
594 +                       int offs = le16_to_cpu(e->e_value_offs);
595 +                       if (offs < border)
596 +                               e->e_value_offs =
597 +                                       cpu_to_le16(offs + size);
598 +                       e = next;
599 +               }
600 +               min_offs += size;
601 +
602 +               /* remove entry */
603 +               border = EXT3_XATTR_LEN(here->e_name_len);
604 +               src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
605 +               size = (char *) last - src;
606 +               if ((char *) here + size > end)
607 +                       printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
608 +                                       __FILE__, __LINE__, here, size, end);
609 +               memmove(here, src, size);
610 +               last = (struct ext3_xattr_entry *) ((char *) last - border);
611 +               *((__u32 *) last) = 0;
612 +       }
613 +       
614 +       if (value) {
615 +               int offs = min_offs - value_len;
616 +               /* use last to create new entry */
617 +               last->e_name_len = strlen(name);
618 +               last->e_name_index = name_index;
619 +               last->e_value_offs = cpu_to_le16(offs);
620 +               last->e_value_size = cpu_to_le32(value_len);
621 +               last->e_hash = last->e_value_block = 0;
622 +               memset(last->e_name, 0, esize);
623 +               memcpy(last->e_name, name, last->e_name_len);
624 +               if (start + offs + value_len > end)
625 +                       printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
626 +                                       __FILE__, __LINE__, start, offs,
627 +                                       value_len, end);
628 +               memcpy(start + offs, value, value_len);
629 +               last = EXT3_XATTR_NEXT(last);
630 +               *((__u32 *) last) = 0;
631 +       }
632 +       
633 +       ext3_mark_iloc_dirty(handle, inode, &iloc);
634 +       brelse(bh);
635 +
636 +       return 0;
637 +}
638 +
639 +/*
640   * ext3_xattr_set()
641   *
642   * Create, replace or remove an extended attribute for this inode. Buffer
643 @@ -566,6 +1050,101 @@
644   */
645  int
646  ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
647 +               const char *name, const void *value, size_t value_len, int flags)
648 +{
649 +       struct ext3_xattr_entry entry;
650 +       int err, where = 0, found = 0, total;
651 +       int free1 = -1, free2 = -1;
652 +       int name_len;
653 +       
654 +       ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
655 +                 name_index, name, value, (long)value_len);
656 +
657 +       if (IS_RDONLY(inode))
658 +               return -EROFS;
659 +       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
660 +               return -EPERM;
661 +       if (value == NULL)
662 +               value_len = 0;
663 +       if (name == NULL)
664 +               return -EINVAL;
665 +       name_len = strlen(name);
666 +       if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
667 +               return -ERANGE;
668 +
669 +       /* try to find attribute in inode body */
670 +       err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
671 +       if (err == 0) {
672 +               /* found EA in inode */
673 +               found = 1;
674 +               where = 0;
675 +       } else if (err == -ENOENT) {
676 +               /* there is no such attribute in inode body */
677 +               /* try to find attribute in dedicated block */
678 +               err = ext3_xattr_block_find(inode, name_index, name,
679 +                                               &entry, &free2);
680 +               if (err != 0 && err != -ENOENT) {
681 +                       /* not found EA in block */
682 +                       goto finish;    
683 +               } else if (err == 0) {
684 +                       /* found EA in block */
685 +                       where = 1;
686 +                       found = 1;
687 +               }
688 +       } else
689 +               goto finish;
690 +
691 +       /* check flags: may replace? may create ? */
692 +       if (found && (flags & XATTR_CREATE)) {
693 +               err = -EEXIST;
694 +               goto finish;
695 +       } else if (!found && (flags & XATTR_REPLACE)) {
696 +               err = -ENODATA;
697 +               goto finish;
698 +       }
699 +
700 +       /* check if we have enough space to store attribute */
701 +       total = EXT3_XATTR_LEN(strlen(name)) + value_len;
702 +       if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
703 +               /* have no enough space */
704 +               err = -ENOSPC;
705 +               goto finish;
706 +       }
707 +       
708 +       /* time to remove attribute */
709 +       if (found) {
710 +               if (where == 0) {
711 +                       /* EA is stored in inode body */
712 +                       ext3_xattr_ibody_set(handle, inode, name_index, name,
713 +                                       NULL, 0, flags);
714 +               } else {
715 +                       /* EA is stored in separated block */
716 +                       ext3_xattr_block_set(handle, inode, name_index, name,
717 +                                       NULL, 0, flags);
718 +               }
719 +       }
720 +
721 +       /* try to store EA in inode body */
722 +       err = ext3_xattr_ibody_set(handle, inode, name_index, name,
723 +                               value, value_len, flags);
724 +       if (err) {
725 +               /* can't store EA in inode body */
726 +               /* try to store in block */
727 +               err = ext3_xattr_block_set(handle, inode, name_index,
728 +                                       name, value, value_len, flags); 
729 +       }
730 +
731 +finish:        
732 +       return err;
733 +}
734 +
735 +/*
736 + * ext3_xattr_block_set()
737 + *
738 + * this routine add/remove/replace attribute in EA block
739 + */
740 +int
741 +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
742                const char *name, const void *value, size_t value_len, int flags)
743  {
744         struct super_block *sb = inode->i_sb;
745 @@ -603,6 +1182,7 @@
746         name_len = strlen(name);
747         if (name_len > 255 || value_len > sb->s_blocksize)
748                 return -ERANGE;
749 +
750         down(&ext3_xattr_sem);
751  
752         if (block) {
753 Index: linux-2.4.24/include/linux/ext3_fs.h
754 ===================================================================
755 --- linux-2.4.24.orig/include/linux/ext3_fs.h   2004-07-13 11:07:18.000000000 +0400
756 +++ linux-2.4.24/include/linux/ext3_fs.h        2004-07-14 18:04:43.000000000 +0400
757 @@ -183,6 +183,7 @@
758  #define EXT3_INDEX_FL                  0x00001000 /* hash-indexed directory */
759  #define EXT3_IMAGIC_FL                 0x00002000 /* AFS directory */
760  #define EXT3_JOURNAL_DATA_FL           0x00004000 /* file data should be journaled */
761 +#define EXT3_EXTRA_ISIZE               0x00008000 /* inode has initialized i_extra_isize */
762  #define EXT3_RESERVED_FL               0x80000000 /* reserved for ext3 lib */
763  
764  #define EXT3_FL_USER_VISIBLE           0x00005FFF /* User visible flags */
765 @@ -264,6 +265,8 @@
766                         __u32   m_i_reserved2[2];
767                 } masix2;
768         } osd2;                         /* OS dependent 2 */
769 +       __u16   i_extra_isize;
770 +       __u16   i_pad1;
771  };
772  
773  #define i_size_high    i_dir_acl
774 Index: linux-2.4.24/include/linux/ext3_fs_i.h
775 ===================================================================
776 --- linux-2.4.24.orig/include/linux/ext3_fs_i.h 2001-11-22 22:46:19.000000000 +0300
777 +++ linux-2.4.24/include/linux/ext3_fs_i.h      2004-07-14 18:00:14.000000000 +0400
778 @@ -62,6 +62,9 @@
779          */
780         loff_t  i_disksize;
781  
782 +       /* on-disk additional length */
783 +       __u16 i_extra_isize;
784 +
785         /*
786          * truncate_sem is for serialising ext3_truncate() against
787          * ext3_getblock().  In the 2.4 ext2 design, great chunks of inode's