diff options
Diffstat (limited to 'fs/ext4/xattr.c')
-rw-r--r-- | fs/ext4/xattr.c | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 34fa37e7744c..cff4f41ced61 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -830,11 +830,10 @@ static void ext4_xattr_inode_free_quota(struct inode *inode, size_t len) dquot_free_inode(inode); } -static int __ext4_xattr_set_credits(struct inode *inode, - struct buffer_head *block_bh, - size_t value_len) +int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode, + struct buffer_head *block_bh, size_t value_len, + bool is_create) { - struct super_block *sb = inode->i_sb; int credits; int blocks; @@ -860,7 +859,7 @@ static int __ext4_xattr_set_credits(struct inode *inode, * In case of inline data, we may push out the data to a block, * so we need to reserve credits for this eventuality */ - if (ext4_has_inline_data(inode)) + if (inode && ext4_has_inline_data(inode)) credits += ext4_writepage_trans_blocks(inode) + 1; /* We are done if ea_inode feature is not enabled. */ @@ -882,19 +881,23 @@ static int __ext4_xattr_set_credits(struct inode *inode, /* Blocks themselves. */ credits += blocks; - /* Dereference ea_inode holding old xattr value. - * Old ea_inode, inode map, block bitmap, group descriptor. - */ - credits += 4; + if (!is_create) { + /* Dereference ea_inode holding old xattr value. + * Old ea_inode, inode map, block bitmap, group descriptor. + */ + credits += 4; - /* Data blocks for old ea_inode. */ - blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits; + /* Data blocks for old ea_inode. */ + blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits; - /* Indirection block or one level of extent tree for old ea_inode. */ - blocks += 1; + /* Indirection block or one level of extent tree for old + * ea_inode. + */ + blocks += 1; - /* Block bitmap and group descriptor updates for each block. */ - credits += blocks * 2; + /* Block bitmap and group descriptor updates for each block. */ + credits += blocks * 2; + } /* We may need to clone the existing xattr block in which case we need * to increment ref counts for existing ea_inodes referenced by it. @@ -2263,7 +2266,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, goto cleanup; } - credits = __ext4_xattr_set_credits(inode, bh, value_len); + credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, + value_len, + flags & XATTR_CREATE); brelse(bh); if (!ext4_handle_has_enough_credits(handle, credits)) { @@ -2370,7 +2375,8 @@ cleanup: return error; } -int ext4_xattr_set_credits(struct inode *inode, size_t value_len, int *credits) +int ext4_xattr_set_credits(struct inode *inode, size_t value_len, + bool is_create, int *credits) { struct buffer_head *bh; int err; @@ -2386,7 +2392,8 @@ int ext4_xattr_set_credits(struct inode *inode, size_t value_len, int *credits) if (IS_ERR(bh)) { err = PTR_ERR(bh); } else { - *credits = __ext4_xattr_set_credits(inode, bh, value_len); + *credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, + value_len, is_create); brelse(bh); err = 0; } @@ -2417,7 +2424,8 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, return error; retry: - error = ext4_xattr_set_credits(inode, value_len, &credits); + error = ext4_xattr_set_credits(inode, value_len, flags & XATTR_CREATE, + &credits); if (error) return error; |