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