Messages in this thread Patch in this message | ![/](/images/icornerl.gif) | | Subject | [RFC] fast EA for ext3 | From | Alex Tomas <> | Date | Sun, 18 May 2003 17:04:39 +0000 |
| |
hi!
this patch implements possibility to store EA into inode body which may be larger 128 bytes in 2.5 kernel. I decided to touch current code as small as possible. format of inode with EA is following:
<old inode> /* 128 bytes */ i_extra_isize /* 2 bytes: how many bytes used _before_ EAs */ i_pad1 /* 2 bytes */ i_uatime /* 4 bytes: access time (useconds) */ i_uctime /* 4 bytes: change time (useconds) */ i_umtime /* 4 bytes: modification time (useconds) */ i_crtim /* 4 bytes: creation time (seconds) */ i_ucrtime /* 4 bytes: creation time (useconds) */ <EA magic> /* 4 bytes: indication that inode has EA in body */ <list of EAs> /* structure is the same current EA uses */
tested with setfattr/getfattr tools. there is patch against e2fsprogs-1.33 which adds ability to show EA stored in inode body.
with best regards, Alex
diff -puNr linux-2.5.69/fs/ext3/ialloc.c edited/fs/ext3/ialloc.c --- linux-2.5.69/fs/ext3/ialloc.c 2003-03-18 14:13:37.000000000 +0300 +++ edited/fs/ext3/ialloc.c 2003-05-11 23:20:51.000000000 +0400 @@ -576,6 +576,17 @@ repeat: ei->i_state = EXT3_STATE_NEW; + ei->i_crtime = CURRENT_TIME; + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { + ei->i_extra_isize = sizeof(__u16) /* i_extra_isize */ + + sizeof(__u16) /* i_pad1 */ + + sizeof(__u32) /* i_uatime */ + + sizeof(__u32) /* i_uctime */ + + sizeof(__u32) /* i_umtime */ + + sizeof(__u32);/* i_udtime */ + } else + ei->i_extra_isize = 0; + unlock_super(sb); ret = inode; if(DQUOT_ALLOC_INODE(inode)) { diff -puNr linux-2.5.69/fs/ext3/xattr.c edited/fs/ext3/xattr.c --- linux-2.5.69/fs/ext3/xattr.c 2003-05-06 21:21:17.000000000 +0400 +++ edited/fs/ext3/xattr.c 2003-05-10 21:51:08.000000000 +0400 @@ -72,15 +72,15 @@ #ifdef EXT3_XATTR_DEBUG # define ea_idebug(inode, f...) do { \ - printk(KERN_DEBUG "inode %s:%ld: ", \ - inode->i_sb->s_id, inode->i_ino); \ + printk(KERN_DEBUG "inode %s:%lu: ", \ + inode->i_sb->s_id, (unsigned long) inode->i_ino); \ printk(f); \ printk("\n"); \ } while (0) # define ea_bdebug(bh, f...) do { \ char b[BDEVNAME_SIZE]; \ - printk(KERN_DEBUG "block %s:%ld: ", \ - bdevname(bh->b_bdev, b), bh->b_blocknr); \ + printk(KERN_DEBUG "block %s:%lu: ", \ + bdevname(bh->b_bdev, b), (unsigned long) bh->b_blocknr); \ printk(f); \ printk("\n"); \ } while (0) @@ -256,17 +256,12 @@ ext3_removexattr(struct dentry *dentry, } /* - * ext3_xattr_get() - * - * Copy an extended attribute into the buffer - * provided, or compute the buffer size required. - * Buffer is NULL to compute the size of the buffer required. + * ext3_xattr_block_get() * - * Returns a negative error number on failure, or the number of bytes - * used / required on success. + * routine looks for attribute in EA block and returns it's value and size */ int -ext3_xattr_get(struct inode *inode, int name_index, const char *name, +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) { struct buffer_head *bh = NULL; @@ -355,9 +350,80 @@ cleanup: } /* - * ext3_xattr_list() + * ext3_xattr_ibode_get() * - * Copy a list of attribute names into the buffer + * routine looks for attribute in inode body and returns it's value and size + */ +int +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + struct ext3_iloc iloc; + char *start, *end; + struct ext3_xattr_entry *last; + int size, name_len = strlen(name), storage_size; + int ret = -ENOENT; + + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) + return -ENOENT; + + ret = ext3_get_inode_loc(inode, &iloc); + if (ret) + return ret; + + storage_size = EXT3_SB(inode->i_sb)->s_inode_size - + EXT3_GOOD_OLD_INODE_SIZE - + EXT3_I(inode)->i_extra_isize - + sizeof(__u32); + start = (char *) iloc.raw_inode + EXT3_GOOD_OLD_INODE_SIZE + + EXT3_I(inode)->i_extra_isize; + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) { + brelse(iloc.bh); + return -ENOENT; + } + start += sizeof(__u32); + end = (char *) iloc.raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; + + last = (struct ext3_xattr_entry *) start; + while (!IS_LAST_ENTRY(last)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); + if (le32_to_cpu(last->e_value_size) > storage_size || + (char *) next >= end) { + ext3_error(inode->i_sb, "ext3_xattr_ibody_get", + "inode %ld", inode->i_ino); + brelse(iloc.bh); + return -EIO; + } + if (name_index == last->e_name_index && + name_len == last->e_name_len && + !memcmp(name, last->e_name, name_len)) + goto found; + last = next; + } + + /* can't find EA */ + brelse(iloc.bh); + return -ENOENT; + +found: + size = le32_to_cpu(last->e_value_size); + if (buffer) { + ret = -ERANGE; + if (buffer_size >= size) { + memcpy(buffer, start + le16_to_cpu(last->e_value_offs), + size); + ret = size; + } + } else + ret = size; + brelse(iloc.bh); + return ret; +} + +/* + * ext3_xattr_get() + * + * Copy an extended attribute into the buffer * provided, or compute the buffer size required. * Buffer is NULL to compute the size of the buffer required. * @@ -365,7 +431,30 @@ cleanup: * used / required on success. */ int -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) +ext3_xattr_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + int err; + + /* try to find attribute in inode body */ + err = ext3_xattr_ibody_get(inode, name_index, name, + buffer, buffer_size); + if (err >= 0) { + /* found EA, return them */ + return err; + } + + /* search was unsuccessful, try to find EA in dedicated block */ + return ext3_xattr_block_get(inode, name_index, name, + buffer, buffer_size); +} + +/* ext3_xattr_ibody_list() + * + * generate list of attributes stored in EA block + */ +int +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) { struct buffer_head *bh = NULL; struct ext3_xattr_entry *entry; @@ -383,7 +472,7 @@ ext3_xattr_list(struct inode *inode, cha if (!bh) return -EIO; ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); + (int) atomic_read(&(bh->b_count)), (int) le32_to_cpu(HDR(bh)->h_refcount)); end = bh->b_data + bh->b_size; if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || HDR(bh)->h_blocks != cpu_to_le32(1)) { @@ -438,6 +527,126 @@ cleanup: return error; } +/* ext3_xattr_ibody_list() + * + * generate list of attributes stored in inode body + */ +int +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size) +{ + struct ext3_iloc iloc; + char *start, *end, *buf; + struct ext3_xattr_entry *last; + int storage_size; + int ret; + int size = 0; + + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) + return 0; + + ret = ext3_get_inode_loc(inode, &iloc); + if (ret) + return ret; + + storage_size = EXT3_SB(inode->i_sb)->s_inode_size - + EXT3_GOOD_OLD_INODE_SIZE - + EXT3_I(inode)->i_extra_isize - + sizeof(__u32); + start = (char *) iloc.raw_inode + EXT3_GOOD_OLD_INODE_SIZE + + EXT3_I(inode)->i_extra_isize; + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) { + brelse(iloc.bh); + return 0; + } + start += sizeof(__u32); + end = (char *) iloc.raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; + + last = (struct ext3_xattr_entry *) start; + while (!IS_LAST_ENTRY(last)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); + struct ext3_xattr_handler *handler; + if (le32_to_cpu(last->e_value_size) > storage_size || + (char *) next >= end) { + ext3_error(inode->i_sb, "ext3_xattr_ibody_list", + "inode %ld", inode->i_ino); + brelse(iloc.bh); + return -EIO; + } + handler = ext3_xattr_handler(last->e_name_index); + if (handler) + size += handler->list(NULL, inode, last->e_name, + last->e_name_len); + last = next; + } + + if (!buffer) { + ret = size; + goto cleanup; + } else { + ret = -ERANGE; + if (size > buffer_size) + goto cleanup; + } + + last = (struct ext3_xattr_entry *) start; + buf = buffer; + while (!IS_LAST_ENTRY(last)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); + struct ext3_xattr_handler *handler; + handler = ext3_xattr_handler(last->e_name_index); + if (handler) + buf += handler->list(buf, inode, last->e_name, + last->e_name_len); + last = next; + } + ret = size; +cleanup: + brelse(iloc.bh); + return ret; +} + +/* + * ext3_xattr_list() + * + * Copy a list of attribute names into the buffer + * provided, or compute the buffer size required. + * Buffer is NULL to compute the size of the buffer required. + * + * Returns a negative error number on failure, or the number of bytes + * used / required on success. + */ +int +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) +{ + int error; + int size = buffer_size; + + /* get list of attributes stored in inode body */ + error = ext3_xattr_ibody_list(inode, buffer, buffer_size); + if (error < 0) { + /* some error occured while collecting + * attributes in inode body */ + return error; + } + size = error; + + /* get list of attributes stored in dedicated block */ + if (buffer) { + buffer_size -= error; + if (buffer_size <= 0) { + buffer = NULL; + buffer_size = 0; + } else + buffer += error; + } + + error = ext3_xattr_block_list(inode, buffer, buffer_size); + if (error < 0) + return error; + + return error + size; +} + /* * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is * not set, set it. @@ -458,6 +667,276 @@ static void ext3_xattr_update_super_bloc } /* + * ext3_xattr_ibody_find() + * + * search attribute and calculate free space in inode body + * NOTE: free space includes space our attribute hold + */ +int +ext3_xattr_ibody_find(struct inode *inode, int name_index, + const char *name, struct ext3_xattr_entry *rentry, int *free) +{ + int err, storage_size; + struct ext3_iloc iloc; + char *start, *end; + struct ext3_xattr_entry *last; + int name_len = strlen(name); + int ret = -ENOENT; + + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) + return ret; + + err = ext3_get_inode_loc(inode, &iloc); + if (err) + return -EIO; + + storage_size = EXT3_SB(inode->i_sb)->s_inode_size - + EXT3_GOOD_OLD_INODE_SIZE - + EXT3_I(inode)->i_extra_isize - + sizeof(__u32); + *free = storage_size - sizeof(__u32); + start = (char *) iloc.raw_inode + EXT3_GOOD_OLD_INODE_SIZE + + EXT3_I(inode)->i_extra_isize; + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) { + brelse(iloc.bh); + return -ENOENT; + } + start += sizeof(__u32); + end = (char *) iloc.raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; + + last = (struct ext3_xattr_entry *) start; + while (!IS_LAST_ENTRY(last)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); + if (le32_to_cpu(last->e_value_size) > storage_size || + (char *) next >= end) { + ext3_error(inode->i_sb, "ext3_xattr_ibody_find", + "inode %ld", inode->i_ino); + brelse(iloc.bh); + return -EIO; + } + + if (name_index == last->e_name_index && + name_len == last->e_name_len && + !memcmp(name, last->e_name, name_len)) { + memcpy(rentry, last, sizeof(struct ext3_xattr_entry)); + ret = 0; + } else { + *free -= EXT3_XATTR_LEN(last->e_name_len); + *free -= le32_to_cpu(last->e_value_size); + } + last = next; + } + + brelse(iloc.bh); + return ret; +} + +/* + * ext3_xattr_block_find() + * + * search attribute and calculate free space in EA block (if it allocated) + * NOTE: free space includes space our attribute hold + */ +int +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name, + struct ext3_xattr_entry *rentry, int *free) +{ + struct buffer_head *bh = NULL; + struct ext3_xattr_entry *entry; + char *end; + int name_len, error = -ENOENT; + + if (!EXT3_I(inode)->i_file_acl) { + *free = inode->i_sb->s_blocksize - + sizeof(struct ext3_xattr_header) - + sizeof(__u32); + return -ENOENT; + } + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + if (!bh) + return -EIO; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); + end = bh->b_data + bh->b_size; + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + HDR(bh)->h_blocks != cpu_to_le32(1)) { +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get", + "inode %ld: bad block %d", inode->i_ino, + EXT3_I(inode)->i_file_acl); + brelse(bh); + return -EIO; + } + /* find named attribute */ + name_len = strlen(name); + *free = bh->b_size - sizeof(__u32); + + entry = FIRST_ENTRY(bh); + while (!IS_LAST_ENTRY(entry)) { + struct ext3_xattr_entry *next = + EXT3_XATTR_NEXT(entry); + if ((char *)next >= end) + goto bad_block; + if (name_index == entry->e_name_index && + name_len == entry->e_name_len && + memcmp(name, entry->e_name, name_len) == 0) { + memcpy(rentry, entry, sizeof(struct ext3_xattr_entry)); + error = 0; + } else { + *free -= EXT3_XATTR_LEN(entry->e_name_len); + *free -= le32_to_cpu(entry->e_value_size); + } + entry = next; + } + brelse(bh); + + return error; +} + +/* + * ext3_xattr_inode_set() + * + * this routine add/remove/replace attribute in inode body + */ +int +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index, + const char *name, const void *value, size_t value_len, + int flags) +{ + /* first, find empty entry */ + int err, storage_size; + struct ext3_iloc iloc; + int free, min_offs; + struct ext3_xattr_entry *last, *next, *here = NULL; + int name_len = strlen(name); + int esize = EXT3_XATTR_LEN(name_len); + char *start, *end; + struct buffer_head *bh; + + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) + return -ENOSPC; + + err = ext3_get_inode_loc(inode, &iloc); + if (err) + return err; + bh = iloc.bh; + + storage_size = EXT3_SB(inode->i_sb)->s_inode_size - + EXT3_GOOD_OLD_INODE_SIZE - + EXT3_I(inode)->i_extra_isize - + sizeof(__u32); + start = (char *) iloc.raw_inode + EXT3_GOOD_OLD_INODE_SIZE + + EXT3_I(inode)->i_extra_isize; + if ((*(__u32*) start) != EXT3_XATTR_MAGIC) { + /* inode had no attributes before */ + *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC); + } + start += sizeof(__u32); + end = (char *) iloc.raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; + min_offs = storage_size; + free = storage_size - sizeof(__u32); + + last = (struct ext3_xattr_entry *) start; + while (!IS_LAST_ENTRY(last)) { + next = EXT3_XATTR_NEXT(last); + if (le32_to_cpu(last->e_value_size) > storage_size || + (char *) next >= end) { + ext3_error(inode->i_sb, "ext3_xattr_ibody_set", + "inode %ld", inode->i_ino); + brelse(bh); + return -EIO; + } + + if (last->e_value_size) { + int offs = le16_to_cpu(last->e_value_offs); + if (offs < min_offs) + min_offs = offs; + } + if (name_index == last->e_name_index && + name_len == last->e_name_len && + !memcmp(name, last->e_name, name_len)) + here = last; + else { + /* we calculate all but our attribute + * because it will be removed before changing */ + free -= EXT3_XATTR_LEN(last->e_name_len); + free -= le32_to_cpu(last->e_value_size); + } + last = next; + } + + if (value && (esize + value_len > free)) { + brelse(bh); + return -ENOSPC; + } + + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) { + brelse(bh); + return err; + } + + if (here) { + /* time to remove old value */ + struct ext3_xattr_entry *e; + int size = le32_to_cpu(here->e_value_size); + int border = le16_to_cpu(here->e_value_offs); + char *src; + + /* move tail */ + memmove(start + min_offs + size, start + min_offs, + border - min_offs); + + /* recalculate offsets */ + e = (struct ext3_xattr_entry *) start; + while (!IS_LAST_ENTRY(e)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e); + int offs = le16_to_cpu(e->e_value_offs); + if (offs < border) + e->e_value_offs = + cpu_to_le16(offs + size); + e = next; + } + min_offs += size; + + /* remove entry */ + border = EXT3_XATTR_LEN(here->e_name_len); + src = (char *) here + EXT3_XATTR_LEN(here->e_name_len); + size = (char *) last - src; + if ((char *) here + size > end) + printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n", + __FILE__, __LINE__, here, size, end); + memmove(here, src, size); + last = (struct ext3_xattr_entry *) ((char *) last - border); + *((__u32 *) last) = 0; + } + + if (value) { + int offs = min_offs - value_len; + /* use last to create new entry */ + last->e_name_len = strlen(name); + last->e_name_index = name_index; + last->e_value_offs = cpu_to_le16(offs); + last->e_value_size = cpu_to_le32(value_len); + last->e_hash = last->e_value_block = 0; + memset(last->e_name, 0, esize); + memcpy(last->e_name, name, last->e_name_len); + if (start + offs + value_len > end) + printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n", + __FILE__, __LINE__, start, offs, + value_len, end); + memcpy(start + offs, value, value_len); + last = EXT3_XATTR_NEXT(last); + *((__u32 *) last) = 0; + } + + ext3_mark_iloc_dirty(handle, inode, &iloc); + brelse(bh); + + return 0; +} + +/* * ext3_xattr_set_handle() * * Create, replace or remove an extended attribute for this inode. Buffer @@ -471,6 +950,103 @@ static void ext3_xattr_update_super_bloc */ int ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, + const char *name, const void *value, size_t value_len, + int flags) +{ + struct ext3_xattr_entry entry; + int err, where = 0, found = 0, total; + int free1 = -1, free2 = -1; + int name_len; + + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", + name_index, name, value, (long)value_len); + + if (IS_RDONLY(inode)) + return -EROFS; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + if (value == NULL) + value_len = 0; + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + if (name_len > 255 || value_len > inode->i_sb->s_blocksize) + return -ERANGE; + down(&ext3_xattr_sem); + + /* try to find attribute in inode body */ + err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1); + if (err == 0) { + /* found EA in inode */ + found = 1; + where = 0; + } else if (err == -ENOENT) { + /* there is no such attribute in inode body */ + /* try to find attribute in dedicated block */ + err = ext3_xattr_block_find(inode, name_index, name, + &entry, &free2); + if (err != 0 && err != -ENOENT) { + /* not found EA in block */ + goto finish; + } + /* found EA in block */ + where = 1; + found = 1; + } else + goto finish; + + /* check flags: may replace? may create ? */ + if (found && (flags & XATTR_CREATE)) { + err = -EEXIST; + goto finish; + } else if (!found && (flags & XATTR_REPLACE)) { + err = -ENODATA; + goto finish; + } + + /* check if we have enough space to store attribute */ + total = EXT3_XATTR_LEN(strlen(name)) + value_len; + if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) { + /* have no enough space */ + err = -ENOSPC; + goto finish; + } + + /* time to remove attribute */ + if (found) { + if (where == 0) { + /* EA is stored in inode body */ + ext3_xattr_ibody_set(handle, inode, name_index, name, + NULL, 0, flags); + } else { + /* EA is stored in separated block */ + ext3_xattr_block_set(handle, inode, name_index, name, + NULL, 0, flags); + } + } + + /* try to store EA in inode body */ + err = ext3_xattr_ibody_set(handle, inode, name_index, name, + value, value_len, flags); + if (err) { + /* can't store EA in inode body */ + /* try to store in block */ + err = ext3_xattr_block_set(handle, inode, name_index, + name, value, value_len, flags); + } + +finish: + up(&ext3_xattr_sem); + return err; +} + +/* + * ext3_xattr_block_set() + * + * this routine add/remove/replace attribute in EA block + */ +int +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index, const char *name, const void *value, size_t value_len, int flags) { @@ -493,23 +1069,8 @@ ext3_xattr_set_handle(handle_t *handle, * towards the end of the block). * end -- Points right after the block pointed to by header. */ - - ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", - name_index, name, value, (long)value_len); - - if (IS_RDONLY(inode)) - return -EROFS; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - if (value == NULL) - value_len = 0; - if (name == NULL) - return -EINVAL; name_len = strlen(name); - if (name_len > 255 || value_len > sb->s_blocksize) - return -ERANGE; - down(&ext3_xattr_sem); - + if (EXT3_I(inode)->i_file_acl) { /* The inode already has an extended attribute block. */ bh = sb_bread(sb, EXT3_I(inode)->i_file_acl); @@ -708,7 +1269,6 @@ cleanup: brelse(bh); if (!(bh && header == HDR(bh))) kfree(header); - up(&ext3_xattr_sem); return error; } @@ -735,7 +1295,7 @@ ext3_xattr_set_handle2(handle_t *handle, */ ea_bdebug(new_bh, "%s block %ld", (old_bh == new_bh) ? "keeping" : "reusing", - new_bh->b_blocknr); + (long int) new_bh->b_blocknr); error = -EDQUOT; if (DQUOT_ALLOC_BLOCK(inode, 1)) diff -puNr linux-2.5.69/fs/ext3/inode.c edited/fs/ext3/inode.c --- linux-2.5.69/fs/ext3/inode.c 2003-05-06 21:21:00.000000000 +0400 +++ edited/fs/ext3/inode.c 2003-05-11 23:39:01.000000000 +0400 @@ -2326,6 +2326,21 @@ void ext3_read_inode(struct inode * inod ei->i_data[block] = iloc.raw_inode->i_block[block]; INIT_LIST_HEAD(&ei->i_orphan); + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { + ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_uatime)) + inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_uatime); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_uctime)) + inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_uctime); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_umtime)) + inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_umtime); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_crtime)) + ei->i_crtime.tv_sec = le32_to_cpu(raw_inode->i_crtime); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_ucrtime)) + ei->i_crtime.tv_nsec = le32_to_cpu(raw_inode->i_ucrtime); + } else + ei->i_extra_isize = 0; + brelse (iloc.bh); if (S_ISREG(inode->i_mode)) { @@ -2456,6 +2471,20 @@ static int ext3_do_update_inode(handle_t else for (block = 0; block < EXT3_N_BLOCKS; block++) raw_inode->i_block[block] = ei->i_data[block]; + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { + raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_uatime)) + raw_inode->i_uatime = cpu_to_le32(inode->i_atime.tv_nsec); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_uctime)) + raw_inode->i_uctime = cpu_to_le32(inode->i_ctime.tv_nsec); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_umtime)) + raw_inode->i_umtime = cpu_to_le32(inode->i_mtime.tv_nsec); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_crtime)) + raw_inode->i_crtime = cpu_to_le32(ei->i_crtime.tv_sec); + if (ei->i_extra_isize >= EXT3_FIELD_END(i_ucrtime)) + raw_inode->i_ucrtime = cpu_to_le32(ei->i_crtime.tv_nsec); + } + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); rc = ext3_journal_dirty_metadata(handle, bh); if (!err) diff -puNr linux-2.5.69/fs/ext3/xattr.h edited/fs/ext3/xattr.h --- linux-2.5.69/fs/ext3/xattr.h 2003-03-14 01:53:36.000000000 +0300 +++ edited/fs/ext3/xattr.h 2003-05-09 13:13:43.000000000 +0400 @@ -75,7 +75,8 @@ extern int ext3_removexattr(struct dentr extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t); extern int ext3_xattr_list(struct inode *, char *, size_t); extern int ext3_xattr_set(struct inode *, int, const char *, const void *, size_t, int); -extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); +extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *,const void *,size_t,int); +extern int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,const void *,size_t,int); extern void ext3_xattr_delete_inode(handle_t *, struct inode *); extern void ext3_xattr_put_super(struct super_block *); diff -puNr linux-2.5.69/include/linux/ext3_fs_i.h edited/include/linux/ext3_fs_i.h --- linux-2.5.69/include/linux/ext3_fs_i.h 2002-12-25 06:03:21.000000000 +0300 +++ edited/include/linux/ext3_fs_i.h 2003-05-11 23:20:51.000000000 +0400 @@ -98,6 +98,12 @@ struct ext3_inode_info { */ struct rw_semaphore truncate_sem; struct inode vfs_inode; + + /* creation time */ + struct timespec i_crtime; + + /* on-disk additional lenght */ + __u16 i_extra_isize; }; #endif /* _LINUX_EXT3_FS_I */ diff -puNr linux-2.5.69/include/linux/ext3_fs.h edited/include/linux/ext3_fs.h --- linux-2.5.69/include/linux/ext3_fs.h 2003-03-18 14:13:37.000000000 +0300 +++ edited/include/linux/ext3_fs.h 2003-05-11 23:10:19.000000000 +0400 @@ -270,8 +270,19 @@ struct ext3_inode { __u32 m_i_reserved2[2]; } masix2; } osd2; /* OS dependent 2 */ + __u16 i_extra_isize; + __u16 i_pad1; + __u32 i_uatime; /* access time (useconds) */ + __u32 i_uctime; /* change time (useconds) */ + __u32 i_umtime; /* modification time (useconds) */ + __u32 i_crtime; /* creation time (seconds) */ + __u32 i_ucrtime; /* creation time (useconds) */ }; +#define EXT3_FIELD_END(field) (offsetof(struct ext3_inode, field) - \ + EXT3_GOOD_OLD_INODE_SIZE + \ + sizeof(*(&((struct ext3_inode *) 0)->field))) + #define i_size_high i_dir_acl #if defined(__KERNEL__) || defined(__linux__) - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| ![\](/images/icornerr.gif) |