4 fs/ext3/xattr.c | 598 +++++++++++++++++++++++++++++++++++++++++++++-
5 include/linux/ext3_fs.h | 2
6 include/linux/ext3_fs_i.h | 3
7 6 files changed, 613 insertions(+), 10 deletions(-)
9 --- linux-2.4.18-chaos/fs/ext3/ialloc.c~ext3-ea-in-inode-2.4.18-chaos 2003-10-08 10:38:03.000000000 +0400
10 +++ linux-2.4.18-chaos-alexey/fs/ext3/ialloc.c 2003-10-08 15:08:45.000000000 +0400
11 @@ -586,6 +586,12 @@ repeat:
12 insert_inode_hash(inode);
13 inode->i_generation = sbi->s_next_generation++;
15 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
16 + ei->i_extra_isize = sizeof(__u16) /* i_extra_isize */
17 + + sizeof(__u16); /* i_pad1 */
19 + ei->i_extra_isize = 0;
21 ei->i_state = EXT3_STATE_NEW;
22 err = ext3_get_inode_loc_new(inode, &iloc, 1);
24 --- linux-2.4.18-chaos/fs/ext3/inode.c~ext3-ea-in-inode-2.4.18-chaos 2003-10-08 10:38:03.000000000 +0400
25 +++ linux-2.4.18-chaos-alexey/fs/ext3/inode.c 2003-10-08 15:08:45.000000000 +0400
26 @@ -2459,6 +2459,11 @@ void ext3_read_inode(struct inode * inod
27 ei->i_data[block] = iloc.raw_inode->i_block[block];
28 INIT_LIST_HEAD(&ei->i_orphan);
30 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
31 + ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
33 + ei->i_extra_isize = 0;
37 if (S_ISREG(inode->i_mode)) {
38 @@ -2523,6 +2528,8 @@ static int ext3_do_update_inode(handle_t
42 + if (ei->i_state & EXT3_STATE_NEW)
43 + memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb));
44 raw_inode->i_mode = cpu_to_le16(inode->i_mode);
45 if(!(test_opt(inode->i_sb, NO_UID32))) {
46 raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
47 @@ -2606,6 +2613,9 @@ static int ext3_do_update_inode(handle_t
48 else for (block = 0; block < EXT3_N_BLOCKS; block++)
49 raw_inode->i_block[block] = ei->i_data[block];
51 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
52 + raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
54 BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
55 rc = ext3_journal_dirty_metadata(handle, bh);
57 --- linux-2.4.18-chaos/fs/ext3/xattr.c~ext3-ea-in-inode-2.4.18-chaos 2003-10-08 10:38:01.000000000 +0400
58 +++ linux-2.4.18-chaos-alexey/fs/ext3/xattr.c 2003-10-12 16:16:44.000000000 +0400
60 static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
61 struct ext3_xattr_header *);
63 +int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
64 + void *, size_t, int);
66 #ifdef CONFIG_EXT3_FS_XATTR_SHARING
68 static int ext3_xattr_cache_insert(struct buffer_head *);
69 @@ -362,17 +365,12 @@ ext3_removexattr(struct dentry *dentry,
75 - * Copy an extended attribute into the buffer
76 - * provided, or compute the buffer size required.
77 - * Buffer is NULL to compute the size of the buffer required.
78 + * ext3_xattr_block_get()
80 - * Returns a negative error number on failure, or the number of bytes
81 - * used / required on success.
82 + * routine looks for attribute in EA block and returns it's value and size
85 -ext3_xattr_get(struct inode *inode, int name_index, const char *name,
86 +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
87 void *buffer, size_t buffer_size)
89 struct buffer_head *bh = NULL;
90 @@ -461,6 +459,94 @@ cleanup:
94 + * ext3_xattr_ibode_get()
96 + * routine looks for attribute in inode body and returns it's value and size
99 +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
100 + void *buffer, size_t buffer_size)
102 + int size, name_len = strlen(name), storage_size;
103 + struct ext3_xattr_entry *last;
104 + struct ext3_inode *raw_inode;
105 + struct ext3_iloc iloc;
109 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
112 + ret = ext3_get_inode_loc(inode, &iloc);
115 + raw_inode = iloc.raw_inode;
117 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
118 + EXT3_GOOD_OLD_INODE_SIZE -
119 + EXT3_I(inode)->i_extra_isize -
121 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
122 + EXT3_I(inode)->i_extra_isize;
123 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
127 + start += sizeof(__u32);
128 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
130 + last = (struct ext3_xattr_entry *) start;
131 + while (!IS_LAST_ENTRY(last)) {
132 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
133 + if (le32_to_cpu(last->e_value_size) > storage_size ||
134 + (char *) next >= end) {
135 + ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
136 + "inode %ld", inode->i_ino);
140 + if (name_index == last->e_name_index &&
141 + name_len == last->e_name_len &&
142 + !memcmp(name, last->e_name, name_len))
147 + /* can't find EA */
152 + size = le32_to_cpu(last->e_value_size);
155 + if (buffer_size >= size) {
156 + memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
166 +int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
167 + void *buffer, size_t buffer_size)
171 + /* try to find attribute in inode body */
172 + err = ext3_xattr_ibody_get(inode, name_index, name,
173 + buffer, buffer_size);
175 + /* search was unsuccessful, try to find EA in dedicated block */
176 + err = ext3_xattr_block_get(inode, name_index, name,
177 + buffer, buffer_size);
184 * Copy a list of attribute names into the buffer
185 @@ -471,7 +557,7 @@ cleanup:
186 * used / required on success.
189 -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
190 +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
192 struct buffer_head *bh = NULL;
193 struct ext3_xattr_entry *entry;
194 @@ -547,6 +633,131 @@ cleanup:
198 +/* ext3_xattr_ibody_list()
200 + * generate list of attributes stored in inode body
203 +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
205 + struct ext3_xattr_entry *last;
206 + struct ext3_inode *raw_inode;
207 + char *start, *end, *buf;
208 + struct ext3_iloc iloc;
213 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
216 + ret = ext3_get_inode_loc(inode, &iloc);
219 + raw_inode = iloc.raw_inode;
221 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
222 + EXT3_GOOD_OLD_INODE_SIZE -
223 + EXT3_I(inode)->i_extra_isize -
225 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
226 + EXT3_I(inode)->i_extra_isize;
227 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
231 + start += sizeof(__u32);
232 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
234 + last = (struct ext3_xattr_entry *) start;
235 + while (!IS_LAST_ENTRY(last)) {
236 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
237 + struct ext3_xattr_handler *handler;
238 + if (le32_to_cpu(last->e_value_size) > storage_size ||
239 + (char *) next >= end) {
240 + ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
241 + "inode %ld", inode->i_ino);
245 + handler = ext3_xattr_handler(last->e_name_index);
247 + size += handler->list(NULL, inode, last->e_name,
257 + if (size > buffer_size)
261 + last = (struct ext3_xattr_entry *) start;
263 + while (!IS_LAST_ENTRY(last)) {
264 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
265 + struct ext3_xattr_handler *handler;
266 + handler = ext3_xattr_handler(last->e_name_index);
268 + buf += handler->list(buf, inode, last->e_name,
279 + * ext3_xattr_list()
281 + * Copy a list of attribute names into the buffer
282 + * provided, or compute the buffer size required.
283 + * Buffer is NULL to compute the size of the buffer required.
285 + * Returns a negative error number on failure, or the number of bytes
286 + * used / required on success.
289 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
292 + int size = buffer_size;
294 + /* get list of attributes stored in inode body */
295 + error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
297 + /* some error occured while collecting
298 + * attributes in inode body */
304 + /* get list of attributes stored in dedicated block */
306 + buffer_size -= error;
307 + if (buffer_size <= 0) {
314 + error = ext3_xattr_block_list(inode, buffer, buffer_size);
316 + /* listing was successful, so we return len */
320 + return error + size;
324 * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
326 @@ -570,6 +781,279 @@ static void ext3_xattr_update_super_bloc
330 + * ext3_xattr_ibody_find()
332 + * search attribute and calculate free space in inode body
333 + * NOTE: free space includes space our attribute hold
336 +ext3_xattr_ibody_find(struct inode *inode, int name_index,
337 + const char *name, struct ext3_xattr_entry *rentry, int *free)
339 + struct ext3_xattr_entry *last;
340 + struct ext3_inode *raw_inode;
341 + int name_len = strlen(name);
342 + int err, storage_size;
343 + struct ext3_iloc iloc;
347 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
350 + err = ext3_get_inode_loc(inode, &iloc);
353 + raw_inode = iloc.raw_inode;
355 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
356 + EXT3_GOOD_OLD_INODE_SIZE -
357 + EXT3_I(inode)->i_extra_isize -
359 + *free = storage_size - sizeof(__u32);
360 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
361 + EXT3_I(inode)->i_extra_isize;
362 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
366 + start += sizeof(__u32);
367 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
369 + last = (struct ext3_xattr_entry *) start;
370 + while (!IS_LAST_ENTRY(last)) {
371 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
372 + if (le32_to_cpu(last->e_value_size) > storage_size ||
373 + (char *) next >= end) {
374 + ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
375 + "inode %ld", inode->i_ino);
380 + if (name_index == last->e_name_index &&
381 + name_len == last->e_name_len &&
382 + !memcmp(name, last->e_name, name_len)) {
383 + memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
386 + *free -= EXT3_XATTR_LEN(last->e_name_len);
387 + *free -= le32_to_cpu(last->e_value_size);
397 + * ext3_xattr_block_find()
399 + * search attribute and calculate free space in EA block (if it allocated)
400 + * NOTE: free space includes space our attribute hold
403 +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
404 + struct ext3_xattr_entry *rentry, int *free)
406 + struct buffer_head *bh = NULL;
407 + struct ext3_xattr_entry *entry;
409 + int name_len, error = -ENOENT;
411 + if (!EXT3_I(inode)->i_file_acl) {
412 + *free = inode->i_sb->s_blocksize -
413 + sizeof(struct ext3_xattr_header) -
417 + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
418 + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
421 + ea_bdebug(bh, "b_count=%d, refcount=%d",
422 + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
423 + end = bh->b_data + bh->b_size;
424 + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
425 + HDR(bh)->h_blocks != cpu_to_le32(1)) {
426 +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get",
427 + "inode %ld: bad block %d", inode->i_ino,
428 + EXT3_I(inode)->i_file_acl);
432 + /* find named attribute */
433 + name_len = strlen(name);
434 + *free = bh->b_size - sizeof(__u32);
436 + entry = FIRST_ENTRY(bh);
437 + while (!IS_LAST_ENTRY(entry)) {
438 + struct ext3_xattr_entry *next =
439 + EXT3_XATTR_NEXT(entry);
440 + if ((char *)next >= end)
442 + if (name_index == entry->e_name_index &&
443 + name_len == entry->e_name_len &&
444 + memcmp(name, entry->e_name, name_len) == 0) {
445 + memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
448 + *free -= EXT3_XATTR_LEN(entry->e_name_len);
449 + *free -= le32_to_cpu(entry->e_value_size);
459 + * ext3_xattr_inode_set()
461 + * this routine add/remove/replace attribute in inode body
464 +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
465 + const char *name, const void *value, size_t value_len,
468 + struct ext3_xattr_entry *last, *next, *here = NULL;
469 + struct ext3_inode *raw_inode;
470 + int name_len = strlen(name);
471 + int esize = EXT3_XATTR_LEN(name_len);
472 + struct buffer_head *bh;
473 + int err, storage_size;
474 + struct ext3_iloc iloc;
475 + int free, min_offs;
478 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
481 + err = ext3_get_inode_loc(inode, &iloc);
484 + raw_inode = iloc.raw_inode;
487 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
488 + EXT3_GOOD_OLD_INODE_SIZE -
489 + EXT3_I(inode)->i_extra_isize -
491 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
492 + EXT3_I(inode)->i_extra_isize;
493 + if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
494 + /* inode had no attributes before */
495 + *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
497 + start += sizeof(__u32);
498 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
499 + min_offs = storage_size;
500 + free = storage_size - sizeof(__u32);
502 + last = (struct ext3_xattr_entry *) start;
503 + while (!IS_LAST_ENTRY(last)) {
504 + next = EXT3_XATTR_NEXT(last);
505 + if (le32_to_cpu(last->e_value_size) > storage_size ||
506 + (char *) next >= end) {
507 + ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
508 + "inode %ld", inode->i_ino);
513 + if (last->e_value_size) {
514 + int offs = le16_to_cpu(last->e_value_offs);
515 + if (offs < min_offs)
518 + if (name_index == last->e_name_index &&
519 + name_len == last->e_name_len &&
520 + !memcmp(name, last->e_name, name_len))
523 + /* we calculate all but our attribute
524 + * because it will be removed before changing */
525 + free -= EXT3_XATTR_LEN(last->e_name_len);
526 + free -= le32_to_cpu(last->e_value_size);
531 + if (value && (esize + value_len > free)) {
536 + err = ext3_reserve_inode_write(handle, inode, &iloc);
543 + /* time to remove old value */
544 + struct ext3_xattr_entry *e;
545 + int size = le32_to_cpu(here->e_value_size);
546 + int border = le16_to_cpu(here->e_value_offs);
550 + memmove(start + min_offs + size, start + min_offs,
551 + border - min_offs);
553 + /* recalculate offsets */
554 + e = (struct ext3_xattr_entry *) start;
555 + while (!IS_LAST_ENTRY(e)) {
556 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
557 + int offs = le16_to_cpu(e->e_value_offs);
560 + cpu_to_le16(offs + size);
566 + border = EXT3_XATTR_LEN(here->e_name_len);
567 + src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
568 + size = (char *) last - src;
569 + if ((char *) here + size > end)
570 + printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
571 + __FILE__, __LINE__, here, size, end);
572 + memmove(here, src, size);
573 + last = (struct ext3_xattr_entry *) ((char *) last - border);
574 + *((__u32 *) last) = 0;
578 + int offs = min_offs - value_len;
579 + /* use last to create new entry */
580 + last->e_name_len = strlen(name);
581 + last->e_name_index = name_index;
582 + last->e_value_offs = cpu_to_le16(offs);
583 + last->e_value_size = cpu_to_le32(value_len);
584 + last->e_hash = last->e_value_block = 0;
585 + memset(last->e_name, 0, esize);
586 + memcpy(last->e_name, name, last->e_name_len);
587 + if (start + offs + value_len > end)
588 + printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
589 + __FILE__, __LINE__, start, offs,
591 + memcpy(start + offs, value, value_len);
592 + last = EXT3_XATTR_NEXT(last);
593 + *((__u32 *) last) = 0;
596 + ext3_mark_iloc_dirty(handle, inode, &iloc);
605 * Create, replace or remove an extended attribute for this inode. Buffer
606 @@ -583,6 +1067,100 @@ static void ext3_xattr_update_super_bloc
609 ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
610 + const char *name, void *value, size_t value_len, int flags)
612 + struct ext3_xattr_entry entry;
613 + int err, where = 0, found = 0, total;
614 + int free1 = -1, free2 = -1;
617 + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
618 + name_index, name, value, (long)value_len);
620 + if (IS_RDONLY(inode))
622 + if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
628 + name_len = strlen(name);
629 + if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
632 + /* try to find attribute in inode body */
633 + err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
635 + /* found EA in inode */
638 + } else if (err == -ENOENT) {
639 + /* there is no such attribute in inode body */
640 + /* try to find attribute in dedicated block */
641 + err = ext3_xattr_block_find(inode, name_index, name,
643 + if (err != 0 && err != -ENOENT) {
644 + /* not found EA in block */
647 + /* found EA in block */
653 + /* check flags: may replace? may create ? */
654 + if (found && (flags & XATTR_CREATE)) {
657 + } else if (!found && (flags & XATTR_REPLACE)) {
662 + /* check if we have enough space to store attribute */
663 + total = EXT3_XATTR_LEN(strlen(name)) + value_len;
664 + if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
665 + /* have no enough space */
670 + /* time to remove attribute */
673 + /* EA is stored in inode body */
674 + ext3_xattr_ibody_set(handle, inode, name_index, name,
677 + /* EA is stored in separated block */
678 + ext3_xattr_block_set(handle, inode, name_index, name,
683 + /* try to store EA in inode body */
684 + err = ext3_xattr_ibody_set(handle, inode, name_index, name,
685 + value, value_len, flags);
687 + /* can't store EA in inode body */
688 + /* try to store in block */
689 + err = ext3_xattr_block_set(handle, inode, name_index,
690 + name, value, value_len, flags);
698 + * ext3_xattr_block_set()
700 + * this routine add/remove/replace attribute in EA block
703 +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
704 const char *name, void *value, size_t value_len, int flags)
706 struct super_block *sb = inode->i_sb;
707 @@ -619,6 +1197,7 @@ ext3_xattr_set(handle_t *handle, struct
708 name_len = strlen(name);
709 if (name_len > 255 || value_len > sb->s_blocksize)
714 if (EXT3_I(inode)->i_file_acl) {
715 @@ -819,6 +1398,7 @@ cleanup:
717 if (!(bh && header == HDR(bh)))
723 --- linux-2.4.18-chaos/include/linux/ext3_fs.h~ext3-ea-in-inode-2.4.18-chaos 2003-10-08 10:38:03.000000000 +0400
724 +++ linux-2.4.18-chaos-alexey/include/linux/ext3_fs.h 2003-10-08 15:08:45.000000000 +0400
725 @@ -264,6 +264,8 @@ struct ext3_inode {
726 __u32 m_i_reserved2[2];
728 } osd2; /* OS dependent 2 */
729 + __u16 i_extra_isize;
733 #define i_size_high i_dir_acl
734 --- linux-2.4.18-chaos/include/linux/ext3_fs_i.h~ext3-ea-in-inode-2.4.18-chaos 2003-10-08 10:38:03.000000000 +0400
735 +++ linux-2.4.18-chaos-alexey/include/linux/ext3_fs_i.h 2003-10-08 15:08:45.000000000 +0400
736 @@ -62,6 +62,9 @@ struct ext3_inode_info {
740 + /* on-disk additional lenght */
741 + __u16 i_extra_isize;
744 * truncate_sem is for serialising ext3_truncate() against
745 * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's
746 --- linux-2.4.18-chaos/fs/ext3/super.c~ext3-ea-in-inode-2.4.18-chaos 2003-10-08 10:38:03.000000000 +0400
747 +++ linux-2.4.18-chaos-alexey/fs/ext3/super.c 2003-10-08 15:08:45.000000000 +0400
748 @@ -1292,7 +1292,9 @@ struct super_block * ext3_read_super (st
750 sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
751 sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
752 - if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
753 + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
754 + (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
755 + (sbi->s_inode_size > blocksize)) {
757 "EXT3-fs: unsupported inode size: %d\n",