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