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