ext4: remove EA inode entry from mbcache on inode eviction

[ Upstream commit 6bc0d63dad7f9f54d381925ee855b402f652fa39 ]

Currently we remove EA inode from mbcache as soon as its xattr refcount
drops to zero. However there can be pending attempts to reuse the inode
and thus refcount handling code has to handle the situation when
refcount increases from zero anyway. So save some work and just keep EA
inode in mbcache until it is getting evicted. At that moment we are sure
following iget() of EA inode will fail anyway (or wait for eviction to
finish and load things from the disk again) and so removing mbcache
entry at that moment is fine and simplifies the code a bit.

CC: stable@vger.kernel.org
Fixes: 82939d7999 ("ext4: convert to mbcache2")
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20220712105436.32204-3-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Jan Kara
2022-07-12 12:54:22 +02:00
committed by Greg Kroah-Hartman
parent 8a9ce3a5b7
commit bb337d8dd1
3 changed files with 11 additions and 16 deletions

View File

@@ -207,6 +207,8 @@ void ext4_evict_inode(struct inode *inode)
trace_ext4_evict_inode(inode); trace_ext4_evict_inode(inode);
if (EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)
ext4_evict_ea_inode(inode);
if (inode->i_nlink) { if (inode->i_nlink) {
/* /*
* When journalling data dirty buffers are tracked only in the * When journalling data dirty buffers are tracked only in the

View File

@@ -434,6 +434,14 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
return err; return err;
} }
/* Remove entry from mbcache when EA inode is getting evicted */
void ext4_evict_ea_inode(struct inode *inode)
{
if (EA_INODE_CACHE(inode))
mb_cache_entry_delete(EA_INODE_CACHE(inode),
ext4_xattr_inode_get_hash(inode), inode->i_ino);
}
static int static int
ext4_xattr_inode_verify_hashes(struct inode *ea_inode, ext4_xattr_inode_verify_hashes(struct inode *ea_inode,
struct ext4_xattr_entry *entry, void *buffer, struct ext4_xattr_entry *entry, void *buffer,
@@ -1019,10 +1027,8 @@ static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode,
static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
int ref_change) int ref_change)
{ {
struct mb_cache *ea_inode_cache = EA_INODE_CACHE(ea_inode);
struct ext4_iloc iloc; struct ext4_iloc iloc;
s64 ref_count; s64 ref_count;
u32 hash;
int ret; int ret;
inode_lock(ea_inode); inode_lock(ea_inode);
@@ -1047,14 +1053,6 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
set_nlink(ea_inode, 1); set_nlink(ea_inode, 1);
ext4_orphan_del(handle, ea_inode); ext4_orphan_del(handle, ea_inode);
if (ea_inode_cache) {
hash = ext4_xattr_inode_get_hash(ea_inode);
mb_cache_entry_create(ea_inode_cache,
GFP_NOFS, hash,
ea_inode->i_ino,
true /* reusable */);
}
} }
} else { } else {
WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld", WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld",
@@ -1067,12 +1065,6 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
clear_nlink(ea_inode); clear_nlink(ea_inode);
ext4_orphan_add(handle, ea_inode); ext4_orphan_add(handle, ea_inode);
if (ea_inode_cache) {
hash = ext4_xattr_inode_get_hash(ea_inode);
mb_cache_entry_delete(ea_inode_cache, hash,
ea_inode->i_ino);
}
} }
} }

View File

@@ -190,6 +190,7 @@ extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *array);
extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
struct ext4_inode *raw_inode, handle_t *handle); struct ext4_inode *raw_inode, handle_t *handle);
extern void ext4_evict_ea_inode(struct inode *inode);
extern const struct xattr_handler *ext4_xattr_handlers[]; extern const struct xattr_handler *ext4_xattr_handlers[];