Skip to content
/ linux Public

Commit 4c2d9da

Browse files
zhangyi089Sasha Levin
authored andcommitted
ext4: don't cache extent during splitting extent
commit 8b4b19a upstream. Caching extents during the splitting process is risky, as it may result in stale extents remaining in the status tree. Moreover, in most cases, the corresponding extent block entries are likely already cached before the split happens, making caching here not particularly useful. Assume we have an unwritten extent, and then DIO writes the first half. [UUUUUUUUUUUUUUUU] on-disk extent U: unwritten extent [UUUUUUUUUUUUUUUU] extent status tree |<- ->| ----> dio write this range First, when ext4_split_extent_at() splits this extent, it truncates the existing extent and then inserts a new one. During this process, this extent status entry may be shrunk, and calls to ext4_find_extent() and ext4_cache_extents() may occur, which could potentially insert the truncated range as a hole into the extent status tree. After the split is completed, this hole is not replaced with the correct status. [UUUUUUU|UUUUUUUU] on-disk extent U: unwritten extent [UUUUUUU|HHHHHHHH] extent status tree H: hole Then, the outer calling functions will not correct this remaining hole extent either. Finally, if we perform a delayed buffer write on this latter part, it will re-insert the delayed extent and cause an error in space accounting. In adition, if the unwritten extent cache is not shrunk during the splitting, ext4_cache_extents() also conflicts with existing extents when caching extents. In the future, we will add checks when caching extents, which will trigger a warning. Therefore, Do not cache extents that are being split. Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com> Reviewed-by: Baokun Li <libaokun1@huawei.com> Cc: stable@kernel.org Message-ID: <20251129103247.686136-6-yi.zhang@huaweicloud.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 4dc65b4 commit 4c2d9da

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

fs/ext4/extents.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,6 +3174,9 @@ static int ext4_split_extent_at(handle_t *handle,
31743174
BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) ==
31753175
(EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2));
31763176

3177+
/* Do not cache extents that are in the process of being modified. */
3178+
flags |= EXT4_EX_NOCACHE;
3179+
31773180
ext_debug(inode, "logical block %llu\n", (unsigned long long)split);
31783181

31793182
ext4_ext_show_leaf(inode, path);
@@ -3344,6 +3347,9 @@ static int ext4_split_extent(handle_t *handle,
33443347
ee_len = ext4_ext_get_actual_len(ex);
33453348
unwritten = ext4_ext_is_unwritten(ex);
33463349

3350+
/* Do not cache extents that are in the process of being modified. */
3351+
flags |= EXT4_EX_NOCACHE;
3352+
33473353
if (map->m_lblk + map->m_len < ee_block + ee_len) {
33483354
split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT;
33493355
flags1 = flags | EXT4_GET_BLOCKS_PRE_IO;

0 commit comments

Comments
 (0)