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 --- linux-2.4.20/fs/ext3/ialloc.c~ext3-ea-in-inode-2.4.20 2003-10-08 23:18:08.000000000 +0400
10 +++ linux-2.4.20-alexey/fs/ext3/ialloc.c 2003-10-12 16:25:21.000000000 +0400
11 @@ -577,6 +577,12 @@ repeat:
12 insert_inode_hash(inode);
13 inode->i_generation = sb->u.ext3_sb.s_next_generation++;
15 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
16 + inode->u.ext3_i.i_extra_isize = sizeof(__u16) /* i_extra_isize */
17 + + sizeof(__u16); /* i_pad1 */
19 + inode->u.ext3_i.i_extra_isize = 0;
21 inode->u.ext3_i.i_state = EXT3_STATE_NEW;
22 err = ext3_get_inode_loc_new(inode, &iloc, 1);
24 --- linux-2.4.20/fs/ext3/inode.c~ext3-ea-in-inode-2.4.20 2003-10-08 23:18:08.000000000 +0400
25 +++ linux-2.4.20-alexey/fs/ext3/inode.c 2003-10-12 16:25:21.000000000 +0400
26 @@ -2209,6 +2209,12 @@ void ext3_read_inode(struct inode * inod
27 inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
28 INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
30 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
31 + inode->u.ext3_i.i_extra_isize =
32 + le16_to_cpu(raw_inode->i_extra_isize);
34 + inode->u.ext3_i.i_extra_isize = 0;
38 if (S_ISREG(inode->i_mode)) {
39 @@ -2274,6 +2280,8 @@ static int ext3_do_update_inode(handle_t
43 + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW)
44 + memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb));
45 raw_inode->i_mode = cpu_to_le16(inode->i_mode);
46 if(!(test_opt(inode->i_sb, NO_UID32))) {
47 raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
48 @@ -2357,6 +2365,10 @@ static int ext3_do_update_inode(handle_t
49 else for (block = 0; block < EXT3_N_BLOCKS; block++)
50 raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
52 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
53 + raw_inode->i_extra_isize =
54 + cpu_to_le16(EXT3_I(inode)->i_extra_isize);
56 BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
57 rc = ext3_journal_dirty_metadata(handle, bh);
59 --- linux-2.4.20/fs/ext3/xattr.c~ext3-ea-in-inode-2.4.20 2003-10-08 23:18:06.000000000 +0400
60 +++ linux-2.4.20-alexey/fs/ext3/xattr.c 2003-10-12 16:26:31.000000000 +0400
62 static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
63 struct ext3_xattr_header *);
65 +int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
66 + const void *, size_t, int);
68 #ifdef CONFIG_EXT3_FS_XATTR_SHARING
70 static int ext3_xattr_cache_insert(struct buffer_head *);
71 @@ -348,17 +351,12 @@ ext3_removexattr(struct dentry *dentry,
77 - * Copy an extended attribute into the buffer
78 - * provided, or compute the buffer size required.
79 - * Buffer is NULL to compute the size of the buffer required.
80 + * ext3_xattr_block_get()
82 - * Returns a negative error number on failure, or the number of bytes
83 - * used / required on success.
84 + * routine looks for attribute in EA block and returns it's value and size
87 -ext3_xattr_get(struct inode *inode, int name_index, const char *name,
88 +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
89 void *buffer, size_t buffer_size)
91 struct buffer_head *bh = NULL;
92 @@ -447,6 +445,94 @@ cleanup:
96 + * ext3_xattr_ibode_get()
98 + * routine looks for attribute in inode body and returns it's value and size
101 +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
102 + void *buffer, size_t buffer_size)
104 + int size, name_len = strlen(name), storage_size;
105 + struct ext3_xattr_entry *last;
106 + struct ext3_inode *raw_inode;
107 + struct ext3_iloc iloc;
111 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
114 + ret = ext3_get_inode_loc(inode, &iloc);
117 + raw_inode = iloc.raw_inode;
119 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
120 + EXT3_GOOD_OLD_INODE_SIZE -
121 + EXT3_I(inode)->i_extra_isize -
123 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
124 + EXT3_I(inode)->i_extra_isize;
125 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
129 + start += sizeof(__u32);
130 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
132 + last = (struct ext3_xattr_entry *) start;
133 + while (!IS_LAST_ENTRY(last)) {
134 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
135 + if (le32_to_cpu(last->e_value_size) > storage_size ||
136 + (char *) next >= end) {
137 + ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
138 + "inode %ld", inode->i_ino);
142 + if (name_index == last->e_name_index &&
143 + name_len == last->e_name_len &&
144 + !memcmp(name, last->e_name, name_len))
149 + /* can't find EA */
154 + size = le32_to_cpu(last->e_value_size);
157 + if (buffer_size >= size) {
158 + memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
168 +int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
169 + void *buffer, size_t buffer_size)
173 + /* try to find attribute in inode body */
174 + err = ext3_xattr_ibody_get(inode, name_index, name,
175 + buffer, buffer_size);
177 + /* search was unsuccessful, try to find EA in dedicated block */
178 + err = ext3_xattr_block_get(inode, name_index, name,
179 + buffer, buffer_size);
186 * Copy a list of attribute names into the buffer
187 @@ -457,7 +543,7 @@ cleanup:
188 * used / required on success.
191 -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
192 +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
194 struct buffer_head *bh = NULL;
195 struct ext3_xattr_entry *entry;
196 @@ -530,6 +616,131 @@ cleanup:
200 +/* ext3_xattr_ibody_list()
202 + * generate list of attributes stored in inode body
205 +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
207 + struct ext3_xattr_entry *last;
208 + struct ext3_inode *raw_inode;
209 + char *start, *end, *buf;
210 + struct ext3_iloc iloc;
215 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
218 + ret = ext3_get_inode_loc(inode, &iloc);
221 + raw_inode = iloc.raw_inode;
223 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
224 + EXT3_GOOD_OLD_INODE_SIZE -
225 + EXT3_I(inode)->i_extra_isize -
227 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
228 + EXT3_I(inode)->i_extra_isize;
229 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
233 + start += sizeof(__u32);
234 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
236 + last = (struct ext3_xattr_entry *) start;
237 + while (!IS_LAST_ENTRY(last)) {
238 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
239 + struct ext3_xattr_handler *handler;
240 + if (le32_to_cpu(last->e_value_size) > storage_size ||
241 + (char *) next >= end) {
242 + ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
243 + "inode %ld", inode->i_ino);
247 + handler = ext3_xattr_handler(last->e_name_index);
249 + size += handler->list(NULL, inode, last->e_name,
259 + if (size > buffer_size)
263 + last = (struct ext3_xattr_entry *) start;
265 + while (!IS_LAST_ENTRY(last)) {
266 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
267 + struct ext3_xattr_handler *handler;
268 + handler = ext3_xattr_handler(last->e_name_index);
270 + buf += handler->list(buf, inode, last->e_name,
281 + * ext3_xattr_list()
283 + * Copy a list of attribute names into the buffer
284 + * provided, or compute the buffer size required.
285 + * Buffer is NULL to compute the size of the buffer required.
287 + * Returns a negative error number on failure, or the number of bytes
288 + * used / required on success.
291 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
294 + int size = buffer_size;
296 + /* get list of attributes stored in inode body */
297 + error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
299 + /* some error occured while collecting
300 + * attributes in inode body */
306 + /* get list of attributes stored in dedicated block */
308 + buffer_size -= error;
309 + if (buffer_size <= 0) {
316 + error = ext3_xattr_block_list(inode, buffer, buffer_size);
318 + /* listing was successful, so we return len */
322 + return error + size;
326 * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
328 @@ -553,6 +764,279 @@ static void ext3_xattr_update_super_bloc
332 + * ext3_xattr_ibody_find()
334 + * search attribute and calculate free space in inode body
335 + * NOTE: free space includes space our attribute hold
338 +ext3_xattr_ibody_find(struct inode *inode, int name_index,
339 + const char *name, struct ext3_xattr_entry *rentry, int *free)
341 + struct ext3_xattr_entry *last;
342 + struct ext3_inode *raw_inode;
343 + int name_len = strlen(name);
344 + int err, storage_size;
345 + struct ext3_iloc iloc;
349 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
352 + err = ext3_get_inode_loc(inode, &iloc);
355 + raw_inode = iloc.raw_inode;
357 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
358 + EXT3_GOOD_OLD_INODE_SIZE -
359 + EXT3_I(inode)->i_extra_isize -
361 + *free = storage_size - sizeof(__u32);
362 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
363 + EXT3_I(inode)->i_extra_isize;
364 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
368 + start += sizeof(__u32);
369 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
371 + last = (struct ext3_xattr_entry *) start;
372 + while (!IS_LAST_ENTRY(last)) {
373 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
374 + if (le32_to_cpu(last->e_value_size) > storage_size ||
375 + (char *) next >= end) {
376 + ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
377 + "inode %ld", inode->i_ino);
382 + if (name_index == last->e_name_index &&
383 + name_len == last->e_name_len &&
384 + !memcmp(name, last->e_name, name_len)) {
385 + memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
388 + *free -= EXT3_XATTR_LEN(last->e_name_len);
389 + *free -= le32_to_cpu(last->e_value_size);
399 + * ext3_xattr_block_find()
401 + * search attribute and calculate free space in EA block (if it allocated)
402 + * NOTE: free space includes space our attribute hold
405 +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
406 + struct ext3_xattr_entry *rentry, int *free)
408 + struct buffer_head *bh = NULL;
409 + struct ext3_xattr_entry *entry;
411 + int name_len, error = -ENOENT;
413 + if (!EXT3_I(inode)->i_file_acl) {
414 + *free = inode->i_sb->s_blocksize -
415 + sizeof(struct ext3_xattr_header) -
419 + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
420 + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
423 + ea_bdebug(bh, "b_count=%d, refcount=%d",
424 + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
425 + end = bh->b_data + bh->b_size;
426 + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
427 + HDR(bh)->h_blocks != cpu_to_le32(1)) {
428 +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get",
429 + "inode %ld: bad block %d", inode->i_ino,
430 + EXT3_I(inode)->i_file_acl);
434 + /* find named attribute */
435 + name_len = strlen(name);
436 + *free = bh->b_size - sizeof(__u32);
438 + entry = FIRST_ENTRY(bh);
439 + while (!IS_LAST_ENTRY(entry)) {
440 + struct ext3_xattr_entry *next =
441 + EXT3_XATTR_NEXT(entry);
442 + if ((char *)next >= end)
444 + if (name_index == entry->e_name_index &&
445 + name_len == entry->e_name_len &&
446 + memcmp(name, entry->e_name, name_len) == 0) {
447 + memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
450 + *free -= EXT3_XATTR_LEN(entry->e_name_len);
451 + *free -= le32_to_cpu(entry->e_value_size);
461 + * ext3_xattr_inode_set()
463 + * this routine add/remove/replace attribute in inode body
466 +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
467 + const char *name, const void *value, size_t value_len,
470 + struct ext3_xattr_entry *last, *next, *here = NULL;
471 + struct ext3_inode *raw_inode;
472 + int name_len = strlen(name);
473 + int esize = EXT3_XATTR_LEN(name_len);
474 + struct buffer_head *bh;
475 + int err, storage_size;
476 + struct ext3_iloc iloc;
477 + int free, min_offs;
480 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
483 + err = ext3_get_inode_loc(inode, &iloc);
486 + raw_inode = iloc.raw_inode;
489 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
490 + EXT3_GOOD_OLD_INODE_SIZE -
491 + EXT3_I(inode)->i_extra_isize -
493 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
494 + EXT3_I(inode)->i_extra_isize;
495 + if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
496 + /* inode had no attributes before */
497 + *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
499 + start += sizeof(__u32);
500 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
501 + min_offs = storage_size;
502 + free = storage_size - sizeof(__u32);
504 + last = (struct ext3_xattr_entry *) start;
505 + while (!IS_LAST_ENTRY(last)) {
506 + next = EXT3_XATTR_NEXT(last);
507 + if (le32_to_cpu(last->e_value_size) > storage_size ||
508 + (char *) next >= end) {
509 + ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
510 + "inode %ld", inode->i_ino);
515 + if (last->e_value_size) {
516 + int offs = le16_to_cpu(last->e_value_offs);
517 + if (offs < min_offs)
520 + if (name_index == last->e_name_index &&
521 + name_len == last->e_name_len &&
522 + !memcmp(name, last->e_name, name_len))
525 + /* we calculate all but our attribute
526 + * because it will be removed before changing */
527 + free -= EXT3_XATTR_LEN(last->e_name_len);
528 + free -= le32_to_cpu(last->e_value_size);
533 + if (value && (esize + value_len > free)) {
538 + err = ext3_reserve_inode_write(handle, inode, &iloc);
545 + /* time to remove old value */
546 + struct ext3_xattr_entry *e;
547 + int size = le32_to_cpu(here->e_value_size);
548 + int border = le16_to_cpu(here->e_value_offs);
552 + memmove(start + min_offs + size, start + min_offs,
553 + border - min_offs);
555 + /* recalculate offsets */
556 + e = (struct ext3_xattr_entry *) start;
557 + while (!IS_LAST_ENTRY(e)) {
558 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
559 + int offs = le16_to_cpu(e->e_value_offs);
562 + cpu_to_le16(offs + size);
568 + border = EXT3_XATTR_LEN(here->e_name_len);
569 + src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
570 + size = (char *) last - src;
571 + if ((char *) here + size > end)
572 + printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
573 + __FILE__, __LINE__, here, size, end);
574 + memmove(here, src, size);
575 + last = (struct ext3_xattr_entry *) ((char *) last - border);
576 + *((__u32 *) last) = 0;
580 + int offs = min_offs - value_len;
581 + /* use last to create new entry */
582 + last->e_name_len = strlen(name);
583 + last->e_name_index = name_index;
584 + last->e_value_offs = cpu_to_le16(offs);
585 + last->e_value_size = cpu_to_le32(value_len);
586 + last->e_hash = last->e_value_block = 0;
587 + memset(last->e_name, 0, esize);
588 + memcpy(last->e_name, name, last->e_name_len);
589 + if (start + offs + value_len > end)
590 + printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
591 + __FILE__, __LINE__, start, offs,
593 + memcpy(start + offs, value, value_len);
594 + last = EXT3_XATTR_NEXT(last);
595 + *((__u32 *) last) = 0;
598 + ext3_mark_iloc_dirty(handle, inode, &iloc);
607 * Create, replace or remove an extended attribute for this inode. Buffer
608 @@ -566,6 +1050,101 @@ static void ext3_xattr_update_super_bloc
611 ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
612 + const char *name, const void *value, size_t value_len, int flags)
614 + struct ext3_xattr_entry entry;
615 + int err, where = 0, found = 0, total;
616 + int free1 = -1, free2 = -1;
619 + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
620 + name_index, name, value, (long)value_len);
622 + if (IS_RDONLY(inode))
624 + if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
630 + name_len = strlen(name);
631 + if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
634 + /* try to find attribute in inode body */
635 + err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
637 + /* found EA in inode */
640 + } else if (err == -ENOENT) {
641 + /* there is no such attribute in inode body */
642 + /* try to find attribute in dedicated block */
643 + err = ext3_xattr_block_find(inode, name_index, name,
645 + if (err != 0 && err != -ENOENT) {
646 + /* not found EA in block */
648 + } else if (err == 0) {
649 + /* found EA in block */
656 + /* check flags: may replace? may create ? */
657 + if (found && (flags & XATTR_CREATE)) {
660 + } else if (!found && (flags & XATTR_REPLACE)) {
665 + /* check if we have enough space to store attribute */
666 + total = EXT3_XATTR_LEN(strlen(name)) + value_len;
667 + if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
668 + /* have no enough space */
673 + /* time to remove attribute */
676 + /* EA is stored in inode body */
677 + ext3_xattr_ibody_set(handle, inode, name_index, name,
680 + /* EA is stored in separated block */
681 + ext3_xattr_block_set(handle, inode, name_index, name,
686 + /* try to store EA in inode body */
687 + err = ext3_xattr_ibody_set(handle, inode, name_index, name,
688 + value, value_len, flags);
690 + /* can't store EA in inode body */
691 + /* try to store in block */
692 + err = ext3_xattr_block_set(handle, inode, name_index,
693 + name, value, value_len, flags);
701 + * ext3_xattr_block_set()
703 + * this routine add/remove/replace attribute in EA block
706 +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
707 const char *name, const void *value, size_t value_len, int flags)
709 struct super_block *sb = inode->i_sb;
710 --- linux-2.4.20/include/linux/ext3_fs.h~ext3-ea-in-inode-2.4.20 2003-10-08 23:18:08.000000000 +0400
711 +++ linux-2.4.20-alexey/include/linux/ext3_fs.h 2003-10-12 16:35:46.000000000 +0400
712 @@ -264,6 +264,8 @@ struct ext3_inode {
713 __u32 m_i_reserved2[2];
715 } osd2; /* OS dependent 2 */
716 + __u16 i_extra_isize;
720 #define i_size_high i_dir_acl
721 --- linux-2.4.20/include/linux/ext3_fs_i.h~ext3-ea-in-inode-2.4.20 2001-11-22 22:46:19.000000000 +0300
722 +++ linux-2.4.20-alexey/include/linux/ext3_fs_i.h 2003-10-12 16:34:14.000000000 +0400
723 @@ -62,6 +62,9 @@ struct ext3_inode_info {
727 + /* on-disk additional length */
728 + __u16 i_extra_isize;
731 * truncate_sem is for serialising ext3_truncate() against
732 * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's
733 --- linux-2.4.20/fs/ext3/super.c~ext3-ea-in-inode-2.4.20 2003-10-08 23:18:09.000000000 +0400
734 +++ linux-2.4.20-alexey/fs/ext3/super.c 2003-10-12 16:25:21.000000000 +0400
735 @@ -1292,8 +1292,10 @@ struct super_block * ext3_read_super (st
737 sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
738 sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
739 - if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
741 + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
742 + (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
743 + (sbi->s_inode_size > blocksize)) {
745 "EXT3-fs: unsupported inode size: %d\n",