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