ext4: avoid unnecessary transaction in ext4_map_blocks() for unwritten extents

When ext4_map_blocks() finds an unwritten extent in the extent cache and
the caller is willing to accept unwritten extents without conversion,
there is no need to start a journal transaction since no metadata update
is required. This avoids unnecessary transaction overhead in the
upcoming iomap writeback path when overwriting already-allocated
unwritten extents.

One thing to be careful about, as the comment in ext4_map_blocks()
states, if the flags contain EXT4_GET_BLOCKS_CREATE, the function will
mark @map as mapped.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: syzbot@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20261009103033.2920530-8-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Zhang Yi 2026-10-09 18:30:08 +08:00 committed by Theodore Ts'o
parent 6585cea3cf
commit 7f373083b4

View File

@ -812,14 +812,25 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
* Note that if blocks have been preallocated
* ext4_ext_map_blocks() returns with buffer head unmapped
*/
if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED)
if (retval > 0) {
/*
* If we need to convert extent to unwritten
* we continue and do the actual work in
* ext4_ext_map_blocks()
* If we need to convert written extent to unwritten or
* convert unwritten extent to written, continue and do
* the actual work in ext4_ext_map_blocks().
*/
if (!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN))
if (map->m_flags & EXT4_MAP_MAPPED &&
!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN))
goto out;
if (map->m_flags & EXT4_MAP_UNWRITTEN &&
(flags & EXT4_GET_BLOCKS_UNWRIT_EXT) &&
!(flags & EXT4_GET_BLOCKS_CONVERT)) {
/* Contains EXT4_GET_BLOCKS_CREATE - mark mapped. */
ret = check_block_validity(inode, map);
if (!ret)
map->m_flags |= EXT4_MAP_MAPPED;
goto out;
}
}
if (!handle) {
handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,