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