Re: [PATCH v4 10/23] ext4: implement mmap path using iomap
From: Ojaswin Mujoo
Date: Wed May 27 2026 - 09:13:09 EST
On Mon, May 11, 2026 at 03:23:30PM +0800, Zhang Yi wrote:
> From: Zhang Yi <yi.zhang@xxxxxxxxxx>
>
> Introduce ext4_iomap_page_mkwrite() to implement the mmap iomap path
> for ext4. The heavy lifting is delegated to iomap_page_mkwrite(), which
> only requires ext4_iomap_buffered_write_ops and
> ext4_iomap_buffered_da_write_ops to allocate and map blocks.
>
> Note that the lock ordering between folio lock and transaction start in
> this path is reversed compared to the buffer_head buffered write path.
> The lock ordering documentation in super.c has been updated accordingly.
>
> Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx>
Looks good, feel free to add:
Reviewed-by: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx>
Regards,
Ojaswin
> ---
> fs/ext4/inode.c | 32 +++++++++++++++++++++++++++++++-
> fs/ext4/super.c | 8 ++++++--
> 2 files changed, 37 insertions(+), 3 deletions(-)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index a80195bd6f20..c6fe42d012fc 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -4020,7 +4020,7 @@ static int ext4_iomap_buffered_do_write_begin(struct inode *inode,
> return -ERANGE;
> if (WARN_ON_ONCE(!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
> return -EINVAL;
> - if (WARN_ON_ONCE(!(flags & IOMAP_WRITE)))
> + if (WARN_ON_ONCE(!(flags & (IOMAP_WRITE | IOMAP_FAULT))))
> return -EINVAL;
>
> if (delalloc)
> @@ -4080,6 +4080,14 @@ static int ext4_iomap_buffered_da_write_end(struct inode *inode, loff_t offset,
> if (iomap->type != IOMAP_DELALLOC || !(iomap->flags & IOMAP_F_NEW))
> return 0;
>
> + /*
> + * iomap_page_mkwrite() will never fail in a way that requires delalloc
> + * extents that it allocated to be revoked. Hence never try to release
> + * them here.
> + */
> + if (flags & IOMAP_FAULT)
> + return 0;
> +
> /* Nothing to do if we've written the entire delalloc extent */
> start_byte = iomap_last_written_block(inode, offset, written);
> end_byte = round_up(offset + length, i_blocksize(inode));
> @@ -7191,6 +7199,23 @@ static int ext4_block_page_mkwrite(struct inode *inode, struct folio *folio,
> return ret;
> }
>
> +static vm_fault_t ext4_iomap_page_mkwrite(struct vm_fault *vmf)
> +{
> + struct inode *inode = file_inode(vmf->vma->vm_file);
> + const struct iomap_ops *iomap_ops;
> +
> + /*
> + * ext4_nonda_switch() could writeback this folio, so have to
> + * call it before lock folio.
> + */
> + if (test_opt(inode->i_sb, DELALLOC) && !ext4_nonda_switch(inode->i_sb))
> + iomap_ops = &ext4_iomap_buffered_da_write_ops;
> + else
> + iomap_ops = &ext4_iomap_buffered_write_ops;
> +
> + return iomap_page_mkwrite(vmf, iomap_ops, NULL);
> +}
> +
> vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf)
> {
> struct vm_area_struct *vma = vmf->vma;
> @@ -7213,6 +7238,11 @@ vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf)
>
> filemap_invalidate_lock_shared(mapping);
>
> + if (ext4_inode_buffered_iomap(inode)) {
> + ret = ext4_iomap_page_mkwrite(vmf);
> + goto out;
> + }
> +
> err = ext4_convert_inline_data(inode);
> if (err)
> goto out_ret;
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 51d87db53543..62bfe05a64bc 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -100,8 +100,12 @@ static const struct fs_parameter_spec ext4_param_specs[];
> * Lock ordering
> *
> * page fault path:
> - * mmap_lock -> sb_start_pagefault -> invalidate_lock (r) -> transaction start
> - * -> page lock -> i_data_sem (rw)
> + * - buffer_head path:
> + * mmap_lock -> sb_start_pagefault -> invalidate_lock (r) ->
> + * transaction start -> folio lock -> i_data_sem (rw)
> + * - iomap path:
> + * mmap_lock -> sb_start_pagefault -> invalidate_lock (r) ->
> + * folio lock -> transaction start -> i_data_sem (rw)
> *
> * buffered write path:
> * sb_start_write -> i_rwsem (w) -> mmap_lock
> --
> 2.52.0
>