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