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