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