Linux EXT4 FS development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Zhang Yi" <yi.zhang@huaweicloud.com>
Cc: tytso@mit.edu, linux-ext4@vger.kernel.org
Subject: Re: [PATCH -next v5 16/32] ext4: implement writeback path using iomap
Date: Fri, 14 Aug 2026 10:19:48 +0000	[thread overview]
Message-ID: <20260814101948.9AE051F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260814093331.1703882-17-yi.zhang@huaweicloud.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] The iomap writeback path queues `iomap_ioend` structures to the `i_rsv_conversion_list`, but the worker function is uninitialized and defaults to `ext4_end_io_rsv_work`, leading to type confusion and memory corruption.
- [Critical] Failure to update `ext4_page_mkwrite()` to use the iomap framework for iomap-enabled inodes causes AB-BA deadlocks and type confusion on `folio->private`.
- [High] The iomap writeback range mapping logic unconditionally expands the allocation length up to the end of the writeback range, incorrectly allocating up to 8MB of unwritten extents into sparse file holes.
- [Medium] Missing WRITE_ONCE() for 64-bit ei->i_disksize allows torn reads on 32-bit systems.
- [Medium] Improper use of min_t() truncates the 64-bit wbc->range_end before comparison, defeating the maximum block cap.
--

--- Patch [16]: [PATCH -next v5 16/32] ext4: implement writeback path using iomap ---
commit 5c1a016c9a25acdff3a66fb714afe96821e567b6
Author: Zhang Yi <yi.zhang@huawei.com>

ext4: implement writeback path using iomap

This commit adds the iomap writeback path for ext4 buffered I/O, introducing 
ext4_iomap_writepages() and the corresponding iomap_writeback_ops. It also 
adds an end I/O work handler to convert unwritten extents and update file 
size upon I/O completion.

> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index d831d1911a6ff..0b3e54e12b78f 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
[ ... ]
> @@ -4134,10 +4135,154 @@ static void ext4_iomap_readahead(struct readahead_control *rac)
> +static int ext4_iomap_map_writeback_range(struct iomap_writepage_ctx *wpc,
> +					  loff_t offset, unsigned int dirty_len)
> +{
[ ... ]
> +	blk_len = dirty_len >> blkbits;
> +	blk_end = min_t(unsigned int, (wpc->wbc->range_end >> blkbits),
> +				      (UINT_MAX - 1));

[Severity: Medium]
Does this code truncate the 64-bit range_end before the comparison?

If wpc->wbc->range_end >> blkbits is evaluated as a 64-bit value but then
cast to unsigned int by min_t(unsigned int, ...), could this truncate the
value to 0 when the shifted value is a multiple of 2^32?

This might disable the writeback batching optimization for specific offsets
in very large files (e.g., syncing around 16TB boundaries).

> +	if (blk_end > index + blk_len)
> +		blk_len = blk_end - index + 1;

[Severity: High]
Will this logic unconditionally expand the block allocation length to the
end of the writeback range?

It looks like blk_len is expanded up to blk_end (which typically represents
the end of the VFS writeback range) without querying the delalloc
reservation length.

If a dirty folio is followed by a hole, could this allocate up to 8MB of
unwritten extents into sparse file holes? This seems like it could
improperly consume disk space and quotas.

> +retry:
> +	map.m_lblk = index;
> +	map.m_len = min_t(unsigned int, MAX_WRITEPAGES_EXTENT_LEN, blk_len);
[ ... ]
> +static const struct iomap_writeback_ops ext4_writeback_ops = {
> +	.writeback_range = ext4_iomap_writeback_range,
> +	.writeback_submit = ext4_iomap_writeback_submit,
> +};
> +
>  static int ext4_iomap_writepages(struct address_space *mapping,
>  				 struct writeback_control *wbc)
>  {

[Severity: Critical]
Since this patch introduces the iomap writeback path, do we also need to
update the mmap fault handler?

The ext4_file_vm_ops.page_mkwrite handler remains hardcoded to
ext4_page_mkwrite(), which uses the legacy ext4_block_page_mkwrite()
logic.

That legacy path attaches a buffer_head to folio->private and starts a
transaction before taking the folio lock.

When ext4_iomap_writepages() later flushes the folio,
iomap_writeback_init() will cast folio->private to struct
iomap_folio_state.

Calling atomic_set() on this state could overwrite the b_this_page list
pointer in the buffer_head, potentially leading to memory corruption and
AB-BA deadlocks between page faulting and writeback.

> -	return 0;
> +	struct inode *inode = mapping->host;
[ ... ]
> diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
> index 0236b6b9785a2..2888e00575615 100644
> --- a/fs/ext4/page-io.c
> +++ b/fs/ext4/page-io.c
[ ... ]
> @@ -547,3 +548,124 @@ void ext4_bio_write_folio(struct ext4_io_submit *io, struct folio *folio,
> +static int ext4_iomap_wb_update_disksize(handle_t *handle, struct inode *inode,
> +					 loff_t end)
> +{
[ ... ]
> +	down_write(&ei->i_data_sem);
> +	new_disksize = min(new_disksize, i_size_read(inode));
> +	if (new_disksize > ei->i_disksize)
> +		ei->i_disksize = new_disksize;

[Severity: Medium]
Does this 64-bit assignment need a WRITE_ONCE() wrapper?

On 32-bit platforms, a plain 64-bit store to ei->i_disksize can be split
into two 32-bit stores.

A concurrent lockless reader calling READ_ONCE(ei->i_disksize) might
observe a torn value, resulting in wildly incorrect disk size values
during concurrent writeback and truncation.

> +	up_write(&ei->i_data_sem);
> +	ret = ext4_mark_inode_dirty(handle, inode);
[ ... ]
> +void ext4_iomap_end_bio(struct bio *bio)
> +{
> +	struct iomap_ioend *ioend = iomap_ioend_from_bio(bio);
> +	struct ext4_inode_info *ei = EXT4_I(ioend->io_inode);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&ei->i_completed_io_lock, flags);
> +	if (list_empty(&ei->i_rsv_conversion_list))
> +		queue_work(EXT4_SB(ioend->io_inode->i_sb)->rsv_conversion_wq,
> +			   &ei->i_rsv_conversion_work);

[Severity: Critical]
Is the worker function for ei->i_rsv_conversion_work properly initialized
for iomap inodes?

It looks like ei->i_rsv_conversion_work is statically initialized to the
legacy ext4_end_io_rsv_work() function in ext4_alloc_inode().

This new iomap writeback path queues iomap_ioend structs to the list, but
it doesn't appear to call INIT_WORK() to reassign the worker function to
the newly introduced ext4_iomap_end_io().

When the work queue executes, wouldn't the legacy ext4_end_io_rsv_work()
iterate over this list and blindly cast iomap_ioend structs to
incompatible ext4_io_end_t structs, resulting in type confusion?

> +	list_add_tail(&ioend->io_list, &ei->i_rsv_conversion_list);
> +	spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260814093331.1703882-1-yi.zhang@huaweicloud.com?part=16

  reply	other threads:[~2026-08-14 10:19 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-14  9:32 [PATCH -next v5 00/32] ext4: use iomap for regular file's buffered I/O path Zhang Yi
2026-08-14  9:33 ` [PATCH -next v5 01/32] ext4: simplify size updating in ext4_setattr() Zhang Yi
2026-08-14 10:02   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 02/32] ext4: factor out ext4_truncate_[up|down]() Zhang Yi
2026-08-14 10:04   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 03/32] ext4: simplify error handling in ext4_setattr() Zhang Yi
2026-08-14 10:12   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 04/32] ext4: skip ordered I/O wait when zeroing beyond i_disksize block Zhang Yi
2026-08-14 10:14   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 05/32] ext4: set EXT4_MAP_NEW flag for delayed allocated blocks Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 06/32] ext4: recheck extent status tree before block allocation Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 07/32] ext4: fix orig_mlen initialization in ext4_map_blocks() Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 08/32] ext4: allow ext4_map_blocks() to start its own transaction handle Zhang Yi
2026-08-14 10:00   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 09/32] ext4: avoid unnecessary transaction in ext4_map_blocks() for unwritten extents Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 10/32] ext4: skip block allocation for holes in the data submission path Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 11/32] ext4: add iomap address space operations for buffered I/O Zhang Yi
2026-08-14 10:04   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 12/32] ext4: implement buffered read path using iomap Zhang Yi
2026-08-14 10:15   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 13/32] ext4: pass out extent seq counter when mapping da blocks Zhang Yi
2026-08-14 10:12   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 14/32] ext4: do not use data=ordered mode for inodes using buffered iomap path Zhang Yi
2026-08-14 10:12   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 15/32] ext4: implement buffered write path using iomap Zhang Yi
2026-08-14 10:40   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 16/32] ext4: implement writeback " Zhang Yi
2026-08-14 10:19   ` sashiko-bot [this message]
2026-08-14  9:33 ` [PATCH -next v5 17/32] ext4: implement mmap " Zhang Yi
2026-08-14 10:35   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 18/32] ext4: implement partial block zero range " Zhang Yi
2026-08-14 10:25   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 19/32] ext4: tolerate unexpected holes in ext4_convert_unwritten_extents() Zhang Yi
2026-08-14 10:09   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 20/32] ext4: add block mapping tracepoints for iomap buffered I/O path Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 21/32] ext4: disable online defrag when inode using " Zhang Yi
2026-08-14 10:08   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 22/32] ext4: add EXT4_STATE_DISKSIZE_GROW_PENDING state bit and helpers Zhang Yi
2026-08-14 10:09   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 23/32] ext4: submit and wait for pending disksize-grow I/O on writeback Zhang Yi
2026-08-14 10:25   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 24/32] ext4: advance i_disksize to i_size upon disksize-grow I/O completion Zhang Yi
2026-08-14 10:25   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 25/32] ext4: defer i_disksize update while DISKSIZE_GROW_PENDING is set Zhang Yi
2026-08-14 10:31   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 26/32] ext4: submit and wait for disksize-grow I/O in fallocate paths Zhang Yi
2026-08-14 10:28   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 27/32] ext4: clear DISKSIZE_GROW_PENDING on truncate or error Zhang Yi
2026-08-14 10:31   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 28/32] ext4: set DISKSIZE_GROW_PENDING after zeroing unaligned EOF block Zhang Yi
2026-08-14 10:18   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 29/32] ext4: add tracepoints for DISKSIZE_GROW_PENDING set, clear, and wait Zhang Yi
2026-08-14 10:18   ` sashiko-bot
2026-08-14  9:33 ` [PATCH -next v5 30/32] ext4: add tracepoints for EOF block zeroing and disksize-grow I/O Zhang Yi
2026-08-14 10:19   ` sashiko-bot
2026-08-14  9:46 ` [PATCH -next v5 31/32] ext4: partially enable iomap for the buffered I/O path of regular files Zhang Yi
2026-08-14 10:39   ` sashiko-bot
2026-08-14  9:46 ` [PATCH -next v5 32/32] ext4: introduce a mount option for iomap buffered I/O path Zhang Yi
2026-08-14 10:25   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260814101948.9AE051F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-ext4@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tytso@mit.edu \
    --cc=yi.zhang@huaweicloud.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox