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