From: Zhang Yi Date: Wed, 23 Apr 2025 08:52:53 +0000 (+0800) Subject: ext4: prevent stale extent cache entries caused by concurrent get es_cache X-Git-Tag: v5.15.186~121 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=603c8dd458dacef0f074a9d4de632f60d9bc7bce;p=thirdparty%2Fkernel%2Fstable.git ext4: prevent stale extent cache entries caused by concurrent get es_cache [ Upstream commit f22a0ef2231a7d8374bb021eb86404d0e9de5a02 ] The EXT4_IOC_GET_ES_CACHE and EXT4_IOC_PRECACHE_EXTENTS currently invokes ext4_ext_precache() to preload the extent cache without holding the inode's i_rwsem. This can result in stale extent cache entries when competing with operations such as ext4_collapse_range() which calls ext4_ext_remove_space() or ext4_ext_shift_extents(). The problem arises when ext4_ext_remove_space() temporarily releases i_data_sem due to insufficient journal credits. During this interval, a concurrent EXT4_IOC_GET_ES_CACHE or EXT4_IOC_PRECACHE_EXTENTS may cache extent entries that are about to be deleted. As a result, these cached entries become stale and inconsistent with the actual extents. Loading the extents cache without holding the inode's i_rwsem or the mapping's invalidate_lock is not permitted besides during the writeback. Fix this by holding the i_rwsem during EXT4_IOC_GET_ES_CACHE and EXT4_IOC_PRECACHE_EXTENTS. Signed-off-by: Zhang Yi Link: https://patch.msgid.link/20250423085257.122685-6-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin --- diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e41a6d642472b..35bc58a26f7f4 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5041,7 +5041,9 @@ int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo, } if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) { + inode_lock_shared(inode); error = ext4_ext_precache(inode); + inode_unlock_shared(inode); if (error) return error; fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 18002b0a908ce..bd90b454c6213 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1130,8 +1130,14 @@ resizefs_out: return 0; } case EXT4_IOC_PRECACHE_EXTENTS: - return ext4_ext_precache(inode); + { + int ret; + inode_lock_shared(inode); + ret = ext4_ext_precache(inode); + inode_unlock_shared(inode); + return ret; + } case FS_IOC_SET_ENCRYPTION_POLICY: if (!ext4_has_feature_encrypt(sb)) return -EOPNOTSUPP;