4 fs/ext3/xattr.c | 597 +++++++++++++++++++++++++++++++++++++++++++++-
5 include/linux/ext3_fs.h | 2
6 include/linux/ext3_fs_i.h | 3
7 6 files changed, 615 insertions(+), 11 deletions(-)
9 Index: linux-2.4.21-chaos/fs/ext3/ialloc.c
10 ===================================================================
11 --- linux-2.4.21-chaos.orig/fs/ext3/ialloc.c 2003-12-12 17:39:10.000000000 +0300
12 +++ linux-2.4.21-chaos/fs/ext3/ialloc.c 2003-12-12 17:39:55.000000000 +0300
14 insert_inode_hash(inode);
15 inode->i_generation = sbi->s_next_generation++;
17 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
18 + EXT3_I(inode)->i_extra_isize = sizeof(__u16) /* i_extra_isize */
19 + + sizeof(__u16); /* i_pad1 */
21 + EXT3_I(inode)->i_extra_isize = 0;
23 inode->u.ext3_i.i_state = EXT3_STATE_NEW;
24 err = ext3_get_inode_loc_new(inode, &iloc, 1);
26 Index: linux-2.4.21-chaos/fs/ext3/inode.c
27 ===================================================================
28 --- linux-2.4.21-chaos.orig/fs/ext3/inode.c 2003-12-12 17:39:11.000000000 +0300
29 +++ linux-2.4.21-chaos/fs/ext3/inode.c 2003-12-12 17:39:55.000000000 +0300
30 @@ -2502,6 +2502,12 @@
31 ei->i_data[block] = iloc.raw_inode->i_block[block];
32 INIT_LIST_HEAD(&ei->i_orphan);
34 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
35 + EXT3_I(inode)->i_extra_isize =
36 + le16_to_cpu(raw_inode->i_extra_isize);
38 + EXT3_I(inode)->i_extra_isize = 0;
40 if (S_ISREG(inode->i_mode)) {
41 inode->i_op = &ext3_file_inode_operations;
42 inode->i_fop = &ext3_file_operations;
47 + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW)
48 + memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb));
49 raw_inode->i_mode = cpu_to_le16(inode->i_mode);
50 if(!(test_opt(inode->i_sb, NO_UID32))) {
51 raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
52 @@ -2646,6 +2654,10 @@
53 else for (block = 0; block < EXT3_N_BLOCKS; block++)
54 raw_inode->i_block[block] = ei->i_data[block];
56 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
57 + raw_inode->i_extra_isize =
58 + cpu_to_le16(EXT3_I(inode)->i_extra_isize);
60 BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
61 rc = ext3_journal_dirty_metadata(handle, bh);
63 Index: linux-2.4.21-chaos/fs/ext3/xattr.c
64 ===================================================================
65 --- linux-2.4.21-chaos.orig/fs/ext3/xattr.c 2003-12-12 17:38:44.000000000 +0300
66 +++ linux-2.4.21-chaos/fs/ext3/xattr.c 2003-12-12 17:42:58.000000000 +0300
69 struct ext3_xattr_header *);
71 +int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
72 + const void *, size_t, int);
74 #ifdef CONFIG_EXT3_FS_XATTR_SHARING
76 static int ext3_xattr_cache_insert(struct buffer_head *);
83 - * Copy an extended attribute into the buffer
84 - * provided, or compute the buffer size required.
85 - * Buffer is NULL to compute the size of the buffer required.
86 + * ext3_xattr_block_get()
88 - * Returns a negative error number on failure, or the number of bytes
89 - * used / required on success.
90 + * routine looks for attribute in EA block and returns it's value and size
93 -ext3_xattr_get(struct inode *inode, int name_index, const char *name,
94 +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
95 void *buffer, size_t buffer_size)
97 struct buffer_head *bh = NULL;
102 + * ext3_xattr_ibode_get()
104 + * routine looks for attribute in inode body and returns it's value and size
107 +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
108 + void *buffer, size_t buffer_size)
110 + int size, name_len = strlen(name), storage_size;
111 + struct ext3_xattr_entry *last;
112 + struct ext3_inode *raw_inode;
113 + struct ext3_iloc iloc;
117 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
120 + ret = ext3_get_inode_loc(inode, &iloc);
123 + raw_inode = iloc.raw_inode;
125 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
126 + EXT3_GOOD_OLD_INODE_SIZE -
127 + EXT3_I(inode)->i_extra_isize -
129 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
130 + EXT3_I(inode)->i_extra_isize;
131 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
135 + start += sizeof(__u32);
136 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
138 + last = (struct ext3_xattr_entry *) start;
139 + while (!IS_LAST_ENTRY(last)) {
140 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
141 + if (le32_to_cpu(last->e_value_size) > storage_size ||
142 + (char *) next >= end) {
143 + ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
144 + "inode %ld", inode->i_ino);
148 + if (name_index == last->e_name_index &&
149 + name_len == last->e_name_len &&
150 + !memcmp(name, last->e_name, name_len))
155 + /* can't find EA */
160 + size = le32_to_cpu(last->e_value_size);
163 + if (buffer_size >= size) {
164 + memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
174 +int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
175 + void *buffer, size_t buffer_size)
179 + /* try to find attribute in inode body */
180 + err = ext3_xattr_ibody_get(inode, name_index, name,
181 + buffer, buffer_size);
183 + /* search was unsuccessful, try to find EA in dedicated block */
184 + err = ext3_xattr_block_get(inode, name_index, name,
185 + buffer, buffer_size);
192 * Copy a list of attribute names into the buffer
194 * used / required on success.
197 -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
198 +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
200 struct buffer_head *bh = NULL;
201 struct ext3_xattr_entry *entry;
202 @@ -446,6 +532,131 @@
206 +/* ext3_xattr_ibody_list()
208 + * generate list of attributes stored in inode body
211 +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
213 + struct ext3_xattr_entry *last;
214 + struct ext3_inode *raw_inode;
215 + char *start, *end, *buf;
216 + struct ext3_iloc iloc;
221 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
224 + ret = ext3_get_inode_loc(inode, &iloc);
227 + raw_inode = iloc.raw_inode;
229 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
230 + EXT3_GOOD_OLD_INODE_SIZE -
231 + EXT3_I(inode)->i_extra_isize -
233 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
234 + EXT3_I(inode)->i_extra_isize;
235 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
239 + start += sizeof(__u32);
240 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
242 + last = (struct ext3_xattr_entry *) start;
243 + while (!IS_LAST_ENTRY(last)) {
244 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
245 + struct ext3_xattr_handler *handler;
246 + if (le32_to_cpu(last->e_value_size) > storage_size ||
247 + (char *) next >= end) {
248 + ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
249 + "inode %ld", inode->i_ino);
253 + handler = ext3_xattr_handler(last->e_name_index);
255 + size += handler->list(NULL, inode, last->e_name,
265 + if (size > buffer_size)
269 + last = (struct ext3_xattr_entry *) start;
271 + while (!IS_LAST_ENTRY(last)) {
272 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
273 + struct ext3_xattr_handler *handler;
274 + handler = ext3_xattr_handler(last->e_name_index);
276 + buf += handler->list(buf, inode, last->e_name,
287 + * ext3_xattr_list()
289 + * Copy a list of attribute names into the buffer
290 + * provided, or compute the buffer size required.
291 + * Buffer is NULL to compute the size of the buffer required.
293 + * Returns a negative error number on failure, or the number of bytes
294 + * used / required on success.
297 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
300 + int size = buffer_size;
302 + /* get list of attributes stored in inode body */
303 + error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
305 + /* some error occured while collecting
306 + * attributes in inode body */
312 + /* get list of attributes stored in dedicated block */
314 + buffer_size -= error;
315 + if (buffer_size <= 0) {
322 + error = ext3_xattr_block_list(inode, buffer, buffer_size);
324 + /* listing was successful, so we return len */
328 + return error + size;
332 * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
334 @@ -480,6 +691,102 @@
337 ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
338 + const char *name, const void *value, size_t value_len,
341 + struct ext3_xattr_entry entry;
342 + int err, where = 0, found = 0, total;
343 + int free1 = -1, free2 = -1;
346 + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
347 + name_index, name, value, (long)value_len);
349 + if (IS_RDONLY(inode))
351 + if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
357 + name_len = strlen(name);
358 + if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
361 + /* try to find attribute in inode body */
362 + err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
364 + /* found EA in inode */
367 + } else if (err == -ENOENT) {
368 + /* there is no such attribute in inode body */
369 + /* try to find attribute in dedicated block */
370 + err = ext3_xattr_block_find(inode, name_index, name,
372 + if (err != 0 && err != -ENOENT) {
373 + /* not found EA in block */
375 + } else if (err == 0) {
376 + /* found EA in block */
383 + /* check flags: may replace? may create ? */
384 + if (found && (flags & XATTR_CREATE)) {
387 + } else if (!found && (flags & XATTR_REPLACE)) {
392 + /* check if we have enough space to store attribute */
393 + total = EXT3_XATTR_LEN(strlen(name)) + value_len;
394 + if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
395 + /* have no enough space */
400 + /* time to remove attribute */
403 + /* EA is stored in inode body */
404 + ext3_xattr_ibody_set(handle, inode, name_index, name,
407 + /* EA is stored in separated block */
408 + ext3_xattr_block_set(handle, inode, name_index, name,
413 + /* try to store EA in inode body */
414 + err = ext3_xattr_ibody_set(handle, inode, name_index, name,
415 + value, value_len, flags);
417 + /* can't store EA in inode body */
418 + /* try to store in block */
419 + err = ext3_xattr_block_set(handle, inode, name_index,
420 + name, value, value_len, flags);
428 + * ext3_xattr_block_set()
430 + * this routine add/remove/replace attribute in EA block
433 +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
434 const char *name, const void *value, size_t value_len,
437 @@ -868,6 +1174,279 @@
441 + * ext3_xattr_ibody_find()
443 + * search attribute and calculate free space in inode body
444 + * NOTE: free space includes space our attribute hold
447 +ext3_xattr_ibody_find(struct inode *inode, int name_index,
448 + const char *name, struct ext3_xattr_entry *rentry, int *free)
450 + struct ext3_xattr_entry *last;
451 + struct ext3_inode *raw_inode;
452 + int name_len = strlen(name);
453 + int err, storage_size;
454 + struct ext3_iloc iloc;
458 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
461 + err = ext3_get_inode_loc(inode, &iloc);
464 + raw_inode = iloc.raw_inode;
466 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
467 + EXT3_GOOD_OLD_INODE_SIZE -
468 + EXT3_I(inode)->i_extra_isize -
470 + *free = storage_size - sizeof(__u32);
471 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
472 + EXT3_I(inode)->i_extra_isize;
473 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
477 + start += sizeof(__u32);
478 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
480 + last = (struct ext3_xattr_entry *) start;
481 + while (!IS_LAST_ENTRY(last)) {
482 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
483 + if (le32_to_cpu(last->e_value_size) > storage_size ||
484 + (char *) next >= end) {
485 + ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
486 + "inode %ld", inode->i_ino);
491 + if (name_index == last->e_name_index &&
492 + name_len == last->e_name_len &&
493 + !memcmp(name, last->e_name, name_len)) {
494 + memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
497 + *free -= EXT3_XATTR_LEN(last->e_name_len);
498 + *free -= le32_to_cpu(last->e_value_size);
508 + * ext3_xattr_block_find()
510 + * search attribute and calculate free space in EA block (if it allocated)
511 + * NOTE: free space includes space our attribute hold
514 +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
515 + struct ext3_xattr_entry *rentry, int *free)
517 + struct buffer_head *bh = NULL;
518 + struct ext3_xattr_entry *entry;
520 + int name_len, error = -ENOENT;
522 + if (!EXT3_I(inode)->i_file_acl) {
523 + *free = inode->i_sb->s_blocksize -
524 + sizeof(struct ext3_xattr_header) -
528 + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
529 + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
532 + ea_bdebug(bh, "b_count=%d, refcount=%d",
533 + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
534 + end = bh->b_data + bh->b_size;
535 + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
536 + HDR(bh)->h_blocks != cpu_to_le32(1)) {
537 +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get",
538 + "inode %ld: bad block %d", inode->i_ino,
539 + EXT3_I(inode)->i_file_acl);
543 + /* find named attribute */
544 + name_len = strlen(name);
545 + *free = bh->b_size - sizeof(__u32);
547 + entry = FIRST_ENTRY(bh);
548 + while (!IS_LAST_ENTRY(entry)) {
549 + struct ext3_xattr_entry *next =
550 + EXT3_XATTR_NEXT(entry);
551 + if ((char *)next >= end)
553 + if (name_index == entry->e_name_index &&
554 + name_len == entry->e_name_len &&
555 + memcmp(name, entry->e_name, name_len) == 0) {
556 + memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
559 + *free -= EXT3_XATTR_LEN(entry->e_name_len);
560 + *free -= le32_to_cpu(entry->e_value_size);
570 + * ext3_xattr_inode_set()
572 + * this routine add/remove/replace attribute in inode body
575 +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
576 + const char *name, const void *value, size_t value_len,
579 + struct ext3_xattr_entry *last, *next, *here = NULL;
580 + struct ext3_inode *raw_inode;
581 + int name_len = strlen(name);
582 + int esize = EXT3_XATTR_LEN(name_len);
583 + struct buffer_head *bh;
584 + int err, storage_size;
585 + struct ext3_iloc iloc;
586 + int free, min_offs;
589 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
592 + err = ext3_get_inode_loc(inode, &iloc);
595 + raw_inode = iloc.raw_inode;
598 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
599 + EXT3_GOOD_OLD_INODE_SIZE -
600 + EXT3_I(inode)->i_extra_isize -
602 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
603 + EXT3_I(inode)->i_extra_isize;
604 + if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
605 + /* inode had no attributes before */
606 + *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
608 + start += sizeof(__u32);
609 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
610 + min_offs = storage_size;
611 + free = storage_size - sizeof(__u32);
613 + last = (struct ext3_xattr_entry *) start;
614 + while (!IS_LAST_ENTRY(last)) {
615 + next = EXT3_XATTR_NEXT(last);
616 + if (le32_to_cpu(last->e_value_size) > storage_size ||
617 + (char *) next >= end) {
618 + ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
619 + "inode %ld", inode->i_ino);
624 + if (last->e_value_size) {
625 + int offs = le16_to_cpu(last->e_value_offs);
626 + if (offs < min_offs)
629 + if (name_index == last->e_name_index &&
630 + name_len == last->e_name_len &&
631 + !memcmp(name, last->e_name, name_len))
634 + /* we calculate all but our attribute
635 + * because it will be removed before changing */
636 + free -= EXT3_XATTR_LEN(last->e_name_len);
637 + free -= le32_to_cpu(last->e_value_size);
642 + if (value && (esize + value_len > free)) {
647 + err = ext3_reserve_inode_write(handle, inode, &iloc);
654 + /* time to remove old value */
655 + struct ext3_xattr_entry *e;
656 + int size = le32_to_cpu(here->e_value_size);
657 + int border = le16_to_cpu(here->e_value_offs);
661 + memmove(start + min_offs + size, start + min_offs,
662 + border - min_offs);
664 + /* recalculate offsets */
665 + e = (struct ext3_xattr_entry *) start;
666 + while (!IS_LAST_ENTRY(e)) {
667 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
668 + int offs = le16_to_cpu(e->e_value_offs);
671 + cpu_to_le16(offs + size);
677 + border = EXT3_XATTR_LEN(here->e_name_len);
678 + src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
679 + size = (char *) last - src;
680 + if ((char *) here + size > end)
681 + printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
682 + __FILE__, __LINE__, here, size, end);
683 + memmove(here, src, size);
684 + last = (struct ext3_xattr_entry *) ((char *) last - border);
685 + *((__u32 *) last) = 0;
689 + int offs = min_offs - value_len;
690 + /* use last to create new entry */
691 + last->e_name_len = strlen(name);
692 + last->e_name_index = name_index;
693 + last->e_value_offs = cpu_to_le16(offs);
694 + last->e_value_size = cpu_to_le32(value_len);
695 + last->e_hash = last->e_value_block = 0;
696 + memset(last->e_name, 0, esize);
697 + memcpy(last->e_name, name, last->e_name_len);
698 + if (start + offs + value_len > end)
699 + printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
700 + __FILE__, __LINE__, start, offs,
702 + memcpy(start + offs, value, value_len);
703 + last = EXT3_XATTR_NEXT(last);
704 + *((__u32 *) last) = 0;
707 + ext3_mark_iloc_dirty(handle, inode, &iloc);
714 * ext3_xattr_set_trans()
716 * Like ext3_xattr_set_handle, but start from an inode. This extended
717 Index: linux-2.4.21-chaos/fs/ext3/super.c
718 ===================================================================
719 --- linux-2.4.21-chaos.orig/fs/ext3/super.c 2003-12-12 17:39:11.000000000 +0300
720 +++ linux-2.4.21-chaos/fs/ext3/super.c 2003-12-12 17:39:55.000000000 +0300
721 @@ -1354,8 +1354,10 @@
723 sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
724 sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
725 - if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
727 + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
728 + (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
729 + (sbi->s_inode_size > blocksize)) {
731 "EXT3-fs: unsupported inode size: %d\n",
734 Index: linux-2.4.21-chaos/include/linux/ext3_fs.h
735 ===================================================================
736 --- linux-2.4.21-chaos.orig/include/linux/ext3_fs.h 2003-12-12 17:39:10.000000000 +0300
737 +++ linux-2.4.21-chaos/include/linux/ext3_fs.h 2003-12-12 17:39:55.000000000 +0300
739 __u32 m_i_reserved2[2];
741 } osd2; /* OS dependent 2 */
742 + __u16 i_extra_isize;
746 #define i_size_high i_dir_acl
747 Index: linux-2.4.21-chaos/include/linux/ext3_fs_i.h
748 ===================================================================
749 --- linux-2.4.21-chaos.orig/include/linux/ext3_fs_i.h 2003-12-05 16:54:33.000000000 +0300
750 +++ linux-2.4.21-chaos/include/linux/ext3_fs_i.h 2003-12-12 17:39:55.000000000 +0300
755 + /* on-disk additional length */
756 + __u16 i_extra_isize;
759 * truncate_sem is for serialising ext3_truncate() against
760 * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's