Re: [PATCH v6 07/31] ext4: allow ext4_map_blocks() to start its own transaction handle
From: Ojaswin Mujoo
Date: Mon Sep 28 2026 - 06:24:34 EST
On Thu, Sep 03, 2026 at 08:35:19PM +0800, Zhang Yi wrote:
> From: Zhang Yi <yi.zhang@xxxxxxxxxx>
>
> Make ext4_map_blocks() start its own transaction handle when the caller
> does not provide one. The handle is started after the lookup path
> confirms that allocation is actually needed, and is stopped at the
> unified out_handle exit path. This avoids unnecessarily starting a
> handle for pure mapping queries. This prepares for the buffered iomap
> writeback conversion, which improves performance for fragile overwrite
> cases.
>
> Suggested-by: Jan Kara <jack@xxxxxxx>
> Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx>
Looks good Zhang,
Reviewed-by: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx>
Regards,
ojaswin
> ---
> fs/ext4/inode.c | 36 +++++++++++++++++++++++++++---------
> 1 file changed, 27 insertions(+), 9 deletions(-)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 73af6d386985..c9dea4ca5caf 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -703,6 +703,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> struct extent_status es;
> int retval;
> int ret = 0;
> + bool internal_handle = false;
> unsigned int orig_mlen;
> #ifdef ES_AGGRESSIVE_TEST
> struct ext4_map_blocks orig_map;
> @@ -787,13 +788,15 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> retval = ext4_map_query_blocks(handle, inode, map, flags);
> up_read((&EXT4_I(inode)->i_data_sem));
> if (retval < 0)
> - return retval;
> + goto out_handle;
>
> found:
> if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
> ret = check_block_validity(inode, map);
> - if (ret != 0)
> - return ret;
> + if (ret != 0) {
> + retval = ret;
> + goto out_handle;
> + }
> }
>
> /* If it is only a block(s) look up */
> @@ -813,8 +816,15 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> * ext4_ext_map_blocks()
> */
> if (!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN))
> - return retval;
> + goto out_handle;
>
> + if (!handle) {
> + handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
> + ext4_chunk_trans_blocks(inode, orig_mlen));
> + if (IS_ERR(handle))
> + return PTR_ERR(handle);
> + internal_handle = true;
> + }
>
> ext4_fc_track_inode(handle, inode);
> /*
> @@ -843,12 +853,14 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> if (retval < 0)
> ext_debug(inode, "failed with err %d\n", retval);
> if (retval <= 0)
> - return retval;
> + goto out_handle;
>
> if (map->m_flags & EXT4_MAP_MAPPED) {
> ret = check_block_validity(inode, map);
> - if (ret != 0)
> - return ret;
> + if (ret != 0) {
> + retval = ret;
> + goto out_handle;
> + }
>
> /*
> * Inodes with freshly allocated blocks where contents will be
> @@ -869,12 +881,18 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
> else
> ret = ext4_jbd2_inode_add_write(handle, inode,
> start_byte, length);
> - if (ret)
> - return ret;
> + if (ret) {
> + retval = ret;
> + goto out_handle;
> + }
> }
> }
> ext4_fc_track_range(handle, inode, map->m_lblk, map->m_lblk +
> map->m_len - 1);
> +
> +out_handle:
> + if (internal_handle)
> + ext4_journal_stop(handle);
> return retval;
> }
>
> --
> 2.52.0
>