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