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