diff options
author | Andreas Dilger <andreas.dilger@intel.com> | 2017-06-22 04:10:32 +0300 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2017-06-22 04:10:32 +0300 |
commit | e50e5129f384ae282adebfb561189cdb19b81cee (patch) | |
tree | d386e2df251f3faa23af1236f8c129bb6ea25b9d /fs/ext4/inode.c | |
parent | e08ac99fa2a25626f573cfa377ef3ddedf2cfe8f (diff) | |
download | linux-e50e5129f384ae282adebfb561189cdb19b81cee.tar.xz |
ext4: xattr-in-inode support
Large xattr support is implemented for EXT4_FEATURE_INCOMPAT_EA_INODE.
If the size of an xattr value is larger than will fit in a single
external block, then the xattr value will be saved into the body
of an external xattr inode.
The also helps support a larger number of xattr, since only the headers
will be stored in the in-inode space or the single external block.
The inode is referenced from the xattr header via "e_value_inum",
which was formerly "e_value_block", but that field was never used.
The e_value_size still contains the xattr size so that listing
xattrs does not need to look up the inode if the data is not accessed.
struct ext4_xattr_entry {
__u8 e_name_len; /* length of name */
__u8 e_name_index; /* attribute name index */
__le16 e_value_offs; /* offset in disk block of value */
__le32 e_value_inum; /* inode in which value is stored */
__le32 e_value_size; /* size of attribute value */
__le32 e_hash; /* hash value of name and value */
char e_name[0]; /* attribute name */
};
The xattr inode is marked with the EXT4_EA_INODE_FL flag and also
holds a back-reference to the owning inode in its i_mtime field,
allowing the ext4/e2fsck to verify the correct inode is accessed.
[ Applied fix by Dan Carpenter to avoid freeing an ERR_PTR. ]
Lustre-Jira: https://jira.hpdd.intel.com/browse/LU-80
Lustre-bugzilla: https://bugzilla.lustre.org/show_bug.cgi?id=4424
Signed-off-by: Kalpak Shah <kalpak.shah@sun.com>
Signed-off-by: James Simmons <uja.ornl@gmail.com>
Signed-off-by: Andreas Dilger <andreas.dilger@intel.com>
Signed-off-by: Tahsin Erdogan <tahsin@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 47604d1352fc..986efd9511ac 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -139,8 +139,6 @@ static void ext4_invalidatepage(struct page *page, unsigned int offset, unsigned int length); static int __ext4_journalled_writepage(struct page *page, unsigned int len); static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh); -static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, - int pextents); /* * Test whether an inode is a fast symlink. @@ -189,6 +187,8 @@ void ext4_evict_inode(struct inode *inode) { handle_t *handle; int err; + int extra_credits = 3; + struct ext4_xattr_ino_array *lea_ino_array = NULL; trace_ext4_evict_inode(inode); @@ -238,8 +238,8 @@ void ext4_evict_inode(struct inode *inode) * protection against it */ sb_start_intwrite(inode->i_sb); - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, - ext4_blocks_for_truncate(inode)+3); + + handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, extra_credits); if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* @@ -251,9 +251,36 @@ void ext4_evict_inode(struct inode *inode) sb_end_intwrite(inode->i_sb); goto no_delete; } - if (IS_SYNC(inode)) ext4_handle_sync(handle); + + /* + * Delete xattr inode before deleting the main inode. + */ + err = ext4_xattr_delete_inode(handle, inode, &lea_ino_array); + if (err) { + ext4_warning(inode->i_sb, + "couldn't delete inode's xattr (err %d)", err); + goto stop_handle; + } + + if (!IS_NOQUOTA(inode)) + extra_credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); + + if (!ext4_handle_has_enough_credits(handle, + ext4_blocks_for_truncate(inode) + extra_credits)) { + err = ext4_journal_extend(handle, + ext4_blocks_for_truncate(inode) + extra_credits); + if (err > 0) + err = ext4_journal_restart(handle, + ext4_blocks_for_truncate(inode) + extra_credits); + if (err != 0) { + ext4_warning(inode->i_sb, + "couldn't extend journal (err %d)", err); + goto stop_handle; + } + } + inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { @@ -277,10 +304,10 @@ void ext4_evict_inode(struct inode *inode) * enough credits left in the handle to remove the inode from * the orphan list and set the dtime field. */ - if (!ext4_handle_has_enough_credits(handle, 3)) { - err = ext4_journal_extend(handle, 3); + if (!ext4_handle_has_enough_credits(handle, extra_credits)) { + err = ext4_journal_extend(handle, extra_credits); if (err > 0) - err = ext4_journal_restart(handle, 3); + err = ext4_journal_restart(handle, extra_credits); if (err != 0) { ext4_warning(inode->i_sb, "couldn't extend journal (err %d)", err); @@ -315,8 +342,12 @@ void ext4_evict_inode(struct inode *inode) ext4_clear_inode(inode); else ext4_free_inode(handle, inode); + ext4_journal_stop(handle); sb_end_intwrite(inode->i_sb); + + if (lea_ino_array != NULL) + ext4_xattr_inode_array_free(inode, lea_ino_array); return; no_delete: ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ @@ -5504,7 +5535,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int lblocks, * * Also account for superblock, inode, quota and xattr blocks */ -static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, +int ext4_meta_trans_blocks(struct inode *inode, int lblocks, int pextents) { ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb); |