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 inode->i_generation = sbi->s_next_generation++;
16 inode->u.ext3_i.i_state = EXT3_STATE_NEW;
17 + inode->u.ext3_i.i_extra_isize =
18 + (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ?
19 + sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0;
21 err = ext3_get_inode_loc_new(inode, &iloc, 1);
23 BUFFER_TRACE(iloc->bh, "get_write_access");
24 Index: linux-2.4.21-chaos/fs/ext3/inode.c
25 ===================================================================
26 --- linux-2.4.21-chaos.orig/fs/ext3/inode.c 2003-12-12 17:39:11.000000000 +0300
27 +++ linux-2.4.21-chaos/fs/ext3/inode.c 2003-12-12 17:39:55.000000000 +0300
28 @@ -2502,6 +2502,12 @@
29 ei->i_data[block] = iloc.raw_inode->i_block[block];
30 INIT_LIST_HEAD(&ei->i_orphan);
32 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
33 + EXT3_I(inode)->i_extra_isize =
34 + le16_to_cpu(raw_inode->i_extra_isize);
36 + EXT3_I(inode)->i_extra_isize = 0;
38 if (S_ISREG(inode->i_mode)) {
39 inode->i_op = &ext3_file_inode_operations;
40 inode->i_fop = &ext3_file_operations;
45 + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW)
46 + memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb));
47 raw_inode->i_mode = cpu_to_le16(inode->i_mode);
48 if(!(test_opt(inode->i_sb, NO_UID32))) {
49 raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
50 @@ -2646,6 +2654,10 @@
51 else for (block = 0; block < EXT3_N_BLOCKS; block++)
52 raw_inode->i_block[block] = ei->i_data[block];
54 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
55 + raw_inode->i_extra_isize =
56 + cpu_to_le16(EXT3_I(inode)->i_extra_isize);
58 BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
59 rc = ext3_journal_dirty_metadata(handle, bh);
61 Index: linux-2.4.21-chaos/fs/ext3/xattr.c
62 ===================================================================
63 --- linux-2.4.21-chaos.orig/fs/ext3/xattr.c 2003-12-12 17:38:44.000000000 +0300
64 +++ linux-2.4.21-chaos/fs/ext3/xattr.c 2003-12-12 17:42:58.000000000 +0300
67 struct ext3_xattr_header *);
69 +int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
70 + const void *, size_t, int);
72 #ifdef CONFIG_EXT3_FS_XATTR_SHARING
74 static int ext3_xattr_cache_insert(struct buffer_head *);
81 - * Copy an extended attribute into the buffer
82 - * provided, or compute the buffer size required.
83 - * Buffer is NULL to compute the size of the buffer required.
84 + * ext3_xattr_block_get()
86 - * Returns a negative error number on failure, or the number of bytes
87 - * used / required on success.
88 + * routine looks for attribute in EA block and returns it's value and size
91 -ext3_xattr_get(struct inode *inode, int name_index, const char *name,
92 +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
93 void *buffer, size_t buffer_size)
95 struct buffer_head *bh = NULL;
100 + * ext3_xattr_ibody_get()
102 + * routine looks for attribute in inode body and returns it's value and size
105 +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
106 + void *buffer, size_t buffer_size)
108 + int size, name_len = strlen(name), storage_size;
109 + struct ext3_xattr_entry *last;
110 + struct ext3_inode *raw_inode;
111 + struct ext3_iloc iloc;
115 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
118 + ret = ext3_get_inode_loc(inode, &iloc);
121 + raw_inode = iloc.raw_inode;
123 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
124 + EXT3_GOOD_OLD_INODE_SIZE -
125 + EXT3_I(inode)->i_extra_isize -
127 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
128 + EXT3_I(inode)->i_extra_isize;
129 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
133 + start += sizeof(__u32);
134 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
136 + last = (struct ext3_xattr_entry *) start;
137 + while (!IS_LAST_ENTRY(last)) {
138 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
139 + if (le32_to_cpu(last->e_value_size) > storage_size ||
140 + (char *) next >= end) {
141 + ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
142 + "inode %ld", inode->i_ino);
146 + if (name_index == last->e_name_index &&
147 + name_len == last->e_name_len &&
148 + !memcmp(name, last->e_name, name_len))
153 + /* can't find EA */
158 + size = le32_to_cpu(last->e_value_size);
161 + if (buffer_size >= size) {
162 + memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
172 +int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
173 + void *buffer, size_t buffer_size)
177 + /* try to find attribute in inode body */
178 + err = ext3_xattr_ibody_get(inode, name_index, name,
179 + buffer, buffer_size);
181 + /* search was unsuccessful, try to find EA in dedicated block */
182 + err = ext3_xattr_block_get(inode, name_index, name,
183 + buffer, buffer_size);
190 * Copy a list of attribute names into the buffer
192 * used / required on success.
195 -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
196 +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
198 struct buffer_head *bh = NULL;
199 struct ext3_xattr_entry *entry;
200 @@ -446,6 +532,131 @@
204 +/* ext3_xattr_ibody_list()
206 + * generate list of attributes stored in inode body
209 +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
211 + struct ext3_xattr_entry *last;
212 + struct ext3_inode *raw_inode;
213 + char *start, *end, *buf;
214 + struct ext3_iloc iloc;
219 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
222 + ret = ext3_get_inode_loc(inode, &iloc);
225 + raw_inode = iloc.raw_inode;
227 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
228 + EXT3_GOOD_OLD_INODE_SIZE -
229 + EXT3_I(inode)->i_extra_isize -
231 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
232 + EXT3_I(inode)->i_extra_isize;
233 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
237 + start += sizeof(__u32);
238 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
240 + last = (struct ext3_xattr_entry *) start;
241 + while (!IS_LAST_ENTRY(last)) {
242 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
243 + struct ext3_xattr_handler *handler;
244 + if (le32_to_cpu(last->e_value_size) > storage_size ||
245 + (char *) next >= end) {
246 + ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
247 + "inode %ld", inode->i_ino);
251 + handler = ext3_xattr_handler(last->e_name_index);
253 + size += handler->list(NULL, inode, last->e_name,
263 + if (size > buffer_size)
267 + last = (struct ext3_xattr_entry *) start;
269 + while (!IS_LAST_ENTRY(last)) {
270 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
271 + struct ext3_xattr_handler *handler;
272 + handler = ext3_xattr_handler(last->e_name_index);
274 + buf += handler->list(buf, inode, last->e_name,
285 + * ext3_xattr_list()
287 + * Copy a list of attribute names into the buffer
288 + * provided, or compute the buffer size required.
289 + * Buffer is NULL to compute the size of the buffer required.
291 + * Returns a negative error number on failure, or the number of bytes
292 + * used / required on success.
295 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
298 + int size = buffer_size;
300 + /* get list of attributes stored in inode body */
301 + error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
303 + /* some error occured while collecting
304 + * attributes in inode body */
310 + /* get list of attributes stored in dedicated block */
312 + buffer_size -= error;
313 + if (buffer_size <= 0) {
320 + error = ext3_xattr_block_list(inode, buffer, buffer_size);
322 + /* listing was successful, so we return len */
326 + return error + size;
330 * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
332 @@ -480,6 +691,102 @@
335 ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
336 + const char *name, const void *value, size_t value_len,
339 + struct ext3_xattr_entry entry;
340 + int err, where = 0, found = 0, total;
341 + int free1 = -1, free2 = -1;
344 + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
345 + name_index, name, value, (long)value_len);
347 + if (IS_RDONLY(inode))
349 + if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
355 + name_len = strlen(name);
356 + if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
359 + /* try to find attribute in inode body */
360 + err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
362 + /* found EA in inode */
365 + } else if (err == -ENOENT) {
366 + /* there is no such attribute in inode body */
367 + /* try to find attribute in dedicated block */
368 + err = ext3_xattr_block_find(inode, name_index, name,
370 + if (err != 0 && err != -ENOENT) {
371 + /* not found EA in block */
373 + } else if (err == 0) {
374 + /* found EA in block */
381 + /* check flags: may replace? may create ? */
382 + if (found && (flags & XATTR_CREATE)) {
385 + } else if (!found && (flags & XATTR_REPLACE)) {
390 + /* check if we have enough space to store attribute */
391 + total = EXT3_XATTR_LEN(strlen(name)) + value_len;
392 + if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
393 + /* have no enough space */
398 + /* time to remove attribute */
401 + /* EA is stored in inode body */
402 + ext3_xattr_ibody_set(handle, inode, name_index, name,
405 + /* EA is stored in separated block */
406 + ext3_xattr_block_set(handle, inode, name_index, name,
411 + /* try to store EA in inode body */
412 + err = ext3_xattr_ibody_set(handle, inode, name_index, name,
413 + value, value_len, flags);
415 + /* can't store EA in inode body */
416 + /* try to store in block */
417 + err = ext3_xattr_block_set(handle, inode, name_index,
418 + name, value, value_len, flags);
426 + * ext3_xattr_block_set()
428 + * this routine add/remove/replace attribute in EA block
431 +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
432 const char *name, const void *value, size_t value_len,
435 @@ -868,6 +1174,279 @@
439 + * ext3_xattr_ibody_find()
441 + * search attribute and calculate free space in inode body
442 + * NOTE: free space includes space our attribute hold
445 +ext3_xattr_ibody_find(struct inode *inode, int name_index,
446 + const char *name, struct ext3_xattr_entry *rentry, int *free)
448 + struct ext3_xattr_entry *last;
449 + struct ext3_inode *raw_inode;
450 + int name_len = strlen(name);
451 + int err, storage_size;
452 + struct ext3_iloc iloc;
456 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
459 + err = ext3_get_inode_loc(inode, &iloc);
462 + raw_inode = iloc.raw_inode;
464 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
465 + EXT3_GOOD_OLD_INODE_SIZE -
466 + EXT3_I(inode)->i_extra_isize -
468 + *free = storage_size - sizeof(__u32);
469 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
470 + EXT3_I(inode)->i_extra_isize;
471 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
475 + start += sizeof(__u32);
476 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
478 + last = (struct ext3_xattr_entry *) start;
479 + while (!IS_LAST_ENTRY(last)) {
480 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
481 + if (le32_to_cpu(last->e_value_size) > storage_size ||
482 + (char *) next >= end) {
483 + ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
484 + "inode %ld", inode->i_ino);
489 + if (name_index == last->e_name_index &&
490 + name_len == last->e_name_len &&
491 + !memcmp(name, last->e_name, name_len)) {
492 + memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
495 + *free -= EXT3_XATTR_LEN(last->e_name_len);
496 + *free -= le32_to_cpu(last->e_value_size);
506 + * ext3_xattr_block_find()
508 + * search attribute and calculate free space in EA block (if it allocated)
509 + * NOTE: free space includes space our attribute hold
512 +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
513 + struct ext3_xattr_entry *rentry, int *free)
515 + struct buffer_head *bh = NULL;
516 + struct ext3_xattr_entry *entry;
518 + int name_len, error = -ENOENT;
520 + if (!EXT3_I(inode)->i_file_acl) {
521 + *free = inode->i_sb->s_blocksize -
522 + sizeof(struct ext3_xattr_header) -
526 + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
527 + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
530 + ea_bdebug(bh, "b_count=%d, refcount=%d",
531 + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
532 + end = bh->b_data + bh->b_size;
533 + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
534 + HDR(bh)->h_blocks != cpu_to_le32(1)) {
535 +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get",
536 + "inode %ld: bad block %d", inode->i_ino,
537 + EXT3_I(inode)->i_file_acl);
541 + /* find named attribute */
542 + name_len = strlen(name);
543 + *free = bh->b_size - sizeof(__u32);
545 + entry = FIRST_ENTRY(bh);
546 + while (!IS_LAST_ENTRY(entry)) {
547 + struct ext3_xattr_entry *next =
548 + EXT3_XATTR_NEXT(entry);
549 + if ((char *)next >= end)
551 + if (name_index == entry->e_name_index &&
552 + name_len == entry->e_name_len &&
553 + memcmp(name, entry->e_name, name_len) == 0) {
554 + memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
557 + *free -= EXT3_XATTR_LEN(entry->e_name_len);
558 + *free -= le32_to_cpu(entry->e_value_size);
568 + * ext3_xattr_inode_set()
570 + * this routine add/remove/replace attribute in inode body
573 +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
574 + const char *name, const void *value, size_t value_len,
577 + struct ext3_xattr_entry *last, *next, *here = NULL;
578 + struct ext3_inode *raw_inode;
579 + int name_len = strlen(name);
580 + int esize = EXT3_XATTR_LEN(name_len);
581 + struct buffer_head *bh;
582 + int err, storage_size;
583 + struct ext3_iloc iloc;
584 + int free, min_offs;
587 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
590 + err = ext3_get_inode_loc(inode, &iloc);
593 + raw_inode = iloc.raw_inode;
596 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
597 + EXT3_GOOD_OLD_INODE_SIZE -
598 + EXT3_I(inode)->i_extra_isize -
600 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
601 + EXT3_I(inode)->i_extra_isize;
602 + if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
603 + /* inode had no attributes before */
604 + *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
606 + start += sizeof(__u32);
607 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
608 + min_offs = storage_size;
609 + free = storage_size - sizeof(__u32);
611 + last = (struct ext3_xattr_entry *) start;
612 + while (!IS_LAST_ENTRY(last)) {
613 + next = EXT3_XATTR_NEXT(last);
614 + if (le32_to_cpu(last->e_value_size) > storage_size ||
615 + (char *) next >= end) {
616 + ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
617 + "inode %ld", inode->i_ino);
622 + if (last->e_value_size) {
623 + int offs = le16_to_cpu(last->e_value_offs);
624 + if (offs < min_offs)
627 + if (name_index == last->e_name_index &&
628 + name_len == last->e_name_len &&
629 + !memcmp(name, last->e_name, name_len))
632 + /* we calculate all but our attribute
633 + * because it will be removed before changing */
634 + free -= EXT3_XATTR_LEN(last->e_name_len);
635 + free -= le32_to_cpu(last->e_value_size);
640 + if (value && (esize + value_len > free)) {
645 + err = ext3_reserve_inode_write(handle, inode, &iloc);
652 + /* time to remove old value */
653 + struct ext3_xattr_entry *e;
654 + int size = le32_to_cpu(here->e_value_size);
655 + int border = le16_to_cpu(here->e_value_offs);
659 + memmove(start + min_offs + size, start + min_offs,
660 + border - min_offs);
662 + /* recalculate offsets */
663 + e = (struct ext3_xattr_entry *) start;
664 + while (!IS_LAST_ENTRY(e)) {
665 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
666 + int offs = le16_to_cpu(e->e_value_offs);
669 + cpu_to_le16(offs + size);
675 + border = EXT3_XATTR_LEN(here->e_name_len);
676 + src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
677 + size = (char *) last - src;
678 + if ((char *) here + size > end)
679 + printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
680 + __FILE__, __LINE__, here, size, end);
681 + memmove(here, src, size);
682 + last = (struct ext3_xattr_entry *) ((char *) last - border);
683 + *((__u32 *) last) = 0;
687 + int offs = min_offs - value_len;
688 + /* use last to create new entry */
689 + last->e_name_len = strlen(name);
690 + last->e_name_index = name_index;
691 + last->e_value_offs = cpu_to_le16(offs);
692 + last->e_value_size = cpu_to_le32(value_len);
693 + last->e_hash = last->e_value_block = 0;
694 + memset(last->e_name, 0, esize);
695 + memcpy(last->e_name, name, last->e_name_len);
696 + if (start + offs + value_len > end)
697 + printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
698 + __FILE__, __LINE__, start, offs,
700 + memcpy(start + offs, value, value_len);
701 + last = EXT3_XATTR_NEXT(last);
702 + *((__u32 *) last) = 0;
705 + ext3_mark_iloc_dirty(handle, inode, &iloc);
712 * ext3_xattr_set_trans()
714 * Like ext3_xattr_set_handle, but start from an inode. This extended
715 Index: linux-2.4.21-chaos/fs/ext3/super.c
716 ===================================================================
717 --- linux-2.4.21-chaos.orig/fs/ext3/super.c 2003-12-12 17:39:11.000000000 +0300
718 +++ linux-2.4.21-chaos/fs/ext3/super.c 2003-12-12 17:39:55.000000000 +0300
719 @@ -1354,8 +1354,10 @@
721 sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
722 sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
723 - if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
725 + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
726 + (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
727 + (sbi->s_inode_size > blocksize)) {
729 "EXT3-fs: unsupported inode size: %d\n",
732 Index: linux-2.4.21-chaos/include/linux/ext3_fs.h
733 ===================================================================
734 --- linux-2.4.21-chaos.orig/include/linux/ext3_fs.h 2003-12-12 17:39:10.000000000 +0300
735 +++ linux-2.4.21-chaos/include/linux/ext3_fs.h 2003-12-12 17:39:55.000000000 +0300
737 __u32 m_i_reserved2[2];
739 } osd2; /* OS dependent 2 */
740 + __u16 i_extra_isize;
744 #define i_size_high i_dir_acl
745 Index: linux-2.4.21-chaos/include/linux/ext3_fs_i.h
746 ===================================================================
747 --- linux-2.4.21-chaos.orig/include/linux/ext3_fs_i.h 2003-12-05 16:54:33.000000000 +0300
748 +++ linux-2.4.21-chaos/include/linux/ext3_fs_i.h 2003-12-12 17:39:55.000000000 +0300
753 + /* on-disk additional length */
754 + __u16 i_extra_isize;
757 * truncate_sem is for serialising ext3_truncate() against
758 * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's