The patch below does not apply to the 4.4-stable tree. If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <stable@xxxxxxxxxxxxxxx>. thanks, greg k-h ------------------ original commit in Linus's tree ------------------ >From de05ca8526796c7e9f7c7282b7f89a818af19818 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o <tytso@xxxxxxx> Date: Fri, 30 Mar 2018 15:42:25 -0400 Subject: [PATCH] ext4: move call to ext4_error() into ext4_xattr_check_block() Refactor the call to EXT4_ERROR_INODE() into ext4_xattr_check_block(). This simplifies the code, and fixes a problem where not all callers of ext4_xattr_check_block() were not resulting in ext4_error() getting called when the xattr block is corrupted. Signed-off-by: Theodore Ts'o <tytso@xxxxxxx> Cc: stable@xxxxxxxxxxxxxxx diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 2077d87b09f2..c030e41818ab 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -225,25 +225,36 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end, } static inline int -ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) +__ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh, + const char *function, unsigned int line) { - int error; + int error = -EFSCORRUPTED; if (buffer_verified(bh)) return 0; if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) - return -EFSCORRUPTED; + goto errout; + error = -EFSBADCRC; if (!ext4_xattr_block_csum_verify(inode, bh)) - return -EFSBADCRC; + goto errout; error = ext4_xattr_check_entries(BFIRST(bh), bh->b_data + bh->b_size, bh->b_data); - if (!error) +errout: + if (error) + __ext4_error_inode(inode, function, line, 0, + "corrupted xattr block %llu", + (unsigned long long) bh->b_blocknr); + else set_buffer_verified(bh); return error; } +#define ext4_xattr_check_block(inode, bh) \ + __ext4_xattr_check_block((inode), (bh), __func__, __LINE__) + + static int __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, void *end, const char *function, unsigned int line) @@ -514,12 +525,9 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; + error = ext4_xattr_check_block(inode, bh); + if (error) goto cleanup; - } ext4_xattr_block_cache_insert(ea_block_cache, bh); entry = BFIRST(bh); error = ext4_xattr_find_entry(&entry, name_index, name, 1); @@ -679,12 +687,9 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; + error = ext4_xattr_check_block(inode, bh); + if (error) goto cleanup; - } ext4_xattr_block_cache_insert(EA_BLOCK_CACHE(inode), bh); error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size); @@ -811,10 +816,9 @@ int ext4_get_inode_usage(struct inode *inode, qsize_t *usage) goto out; } - if (ext4_xattr_check_block(inode, bh)) { - ret = -EFSCORRUPTED; + ret = ext4_xattr_check_block(inode, bh); + if (ret) goto out; - } for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) @@ -1796,12 +1800,9 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, ea_bdebug(bs->bh, "b_count=%d, refcount=%d", atomic_read(&(bs->bh->b_count)), le32_to_cpu(BHDR(bs->bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bs->bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; + error = ext4_xattr_check_block(inode, bs->bh); + if (error) goto cleanup; - } /* Find the named attribute. */ bs->s.base = BHDR(bs->bh); bs->s.first = BFIRST(bs->bh); @@ -2724,13 +2725,9 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, error = -EIO; if (!bh) goto cleanup; - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; - brelse(bh); + error = ext4_xattr_check_block(inode, bh); + if (error) goto cleanup; - } base = BHDR(bh); end = bh->b_data + bh->b_size; min_offs = end - base; @@ -2887,11 +2884,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, goto cleanup; } error = ext4_xattr_check_block(inode, bh); - if (error) { - EXT4_ERROR_INODE(inode, "bad block %llu (error %d)", - EXT4_I(inode)->i_file_acl, error); + if (error) goto cleanup; - } if (ext4_has_feature_ea_inode(inode->i_sb)) { for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry);