Skip to content

Commit 8865cd6

Browse files
matthiasgoergensgregkh
authored andcommitted
ext4: stop retrying saturated xattr cache entries
commit 54b6bd4 upstream. ext4_xattr_block_set() retries when a cache entry selected for reuse has a saturated reference count after taking the buffer lock. The retry returns to the mbcache lookup without making that entry ineligible, so it can select the same unusable entry indefinitely. A task spinning there can hold the parent directory's i_rwsem and leave concurrent rmdir callers blocked. Normally a reusable entry has a reference count below EXT4_XATTR_REFCOUNT_MAX because the count and MBE_REUSABLE_B are updated under the same buffer lock. A corrupted filesystem can violate that invariant. The syzbot reproducer reports allocator and xattr corruption before triggering this retry loop. Check the untrusted on-disk count before incrementing it, avoiding overflow, and clear MBE_REUSABLE_B when it is already saturated. The next lookup then skips the entry that was just proven unusable. This mirrors the normal transition at EXT4_XATTR_REFCOUNT_MAX; the release path marks the entry reusable again on the exact 1024-to-1023 transition. Using the same QEMU harness and guest parameters, current unpatched Linux hung in 6 of 8 420-second trials with the do_rmdir signature; representative NMI backtraces caught the owner spinning in ext4_xattr_block_set(). The patched kernel completed 28 of 28 trials without a hung-task report; the final twelve trials exercised the reviewed overflow-safe form of the change. syzbot's patch testing also completed without reproducing the hang. Reported-and-tested-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=e68dbebd9617a9250e8d Fixes: 65f8b80 ("ext4: fix race when reusing xattr blocks") Cc: stable@vger.kernel.org Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com> Reviewed-by: Jan Kara <jack@suse.cz> Reported-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com Tested-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com Link: https://patch.msgid.link/20260802065941.1726052-1-matthias.goergens@gmail.com Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 5dc59fc commit 8865cd6

1 file changed

Lines changed: 4 additions & 2 deletions

File tree

fs/ext4/xattr.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,12 +2017,13 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
20172017
* stable so we can check the additional
20182018
* reference fits.
20192019
*/
2020-
ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1;
2021-
if (ref > EXT4_XATTR_REFCOUNT_MAX) {
2020+
ref = le32_to_cpu(BHDR(new_bh)->h_refcount);
2021+
if (ref >= EXT4_XATTR_REFCOUNT_MAX) {
20222022
/*
20232023
* Undo everything and check mbcache
20242024
* again.
20252025
*/
2026+
clear_bit(MBE_REUSABLE_B, &ce->e_flags);
20262027
unlock_buffer(new_bh);
20272028
dquot_free_block(inode,
20282029
EXT4_C2B(EXT4_SB(sb),
@@ -2033,6 +2034,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
20332034
new_bh = NULL;
20342035
goto inserted;
20352036
}
2037+
ref++;
20362038
BHDR(new_bh)->h_refcount = cpu_to_le32(ref);
20372039
if (ref == EXT4_XATTR_REFCOUNT_MAX)
20382040
clear_bit(MBE_REUSABLE_B, &ce->e_flags);

0 commit comments

Comments
 (0)