ext4: prevent stale extent cache entries caused by concurrent fiemap
The ext4_fiemap() currently invokes ext4_ext_precache() and iomap_fiemap() to preload the extent cache and query mapping information 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_fiemap() 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 in ext4_fiemap(). Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Link: https://patch.msgid.link/20250423085257.122685-5-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
402e38e6b7
commit
151ff9325e
|
|
@ -4963,10 +4963,11 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
{
|
||||
int error = 0;
|
||||
|
||||
inode_lock_shared(inode);
|
||||
if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) {
|
||||
error = ext4_ext_precache(inode);
|
||||
if (error)
|
||||
return error;
|
||||
goto unlock;
|
||||
fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE;
|
||||
}
|
||||
|
||||
|
|
@ -4977,15 +4978,19 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
*/
|
||||
error = ext4_fiemap_check_ranges(inode, start, &len);
|
||||
if (error)
|
||||
return error;
|
||||
goto unlock;
|
||||
|
||||
if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
|
||||
fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR;
|
||||
return iomap_fiemap(inode, fieinfo, start, len,
|
||||
&ext4_iomap_xattr_ops);
|
||||
error = iomap_fiemap(inode, fieinfo, start, len,
|
||||
&ext4_iomap_xattr_ops);
|
||||
} else {
|
||||
error = iomap_fiemap(inode, fieinfo, start, len,
|
||||
&ext4_iomap_report_ops);
|
||||
}
|
||||
|
||||
return iomap_fiemap(inode, fieinfo, start, len, &ext4_iomap_report_ops);
|
||||
unlock:
|
||||
inode_unlock_shared(inode);
|
||||
return error;
|
||||
}
|
||||
|
||||
int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
|
|
|
|||
Loading…
Reference in New Issue