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