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