* [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow
@ 2026-06-18 5:38 Morduan Zang
2026-06-18 9:08 ` Christoph Hellwig
2026-06-19 8:25 ` Christian Brauner
0 siblings, 2 replies; 5+ messages in thread
From: Morduan Zang @ 2026-06-18 5:38 UTC (permalink / raw)
To: brauner; +Cc: linux-fsdevel, linux-xfs, djwong, Morduan Zang
iomap: fix zero padding data issue in concurrent append writes
changed ioend accounting so that io_size tracks only valid data
within EOF. This trims io_size when a writeback range extends
past end_pos:
ioend->io_size += map_len;
if (ioend->io_offset + ioend->io_size > end_pos)
ioend->io_size = end_pos - ioend->io_offset;
However, ioend can be created before a concurrent truncate shrinks
the file. In that case, end_pos can move below ioend->io_offset
before the trim happens. The subtraction then becomes negative, but
the result is stored in size_t io_size, causing an unsigned wrap to
a huge value.
A wrapped io_size can mislead append detection and corrupt
completion-time size handling, since filesystem end_io paths consume
io_size for decisions such as on-disk EOF updates and unwritten/COW
completion ranges.
Fix this by clamping io_size to zero when EOF has moved to or before
the ioend start offset. This preserves the original intent of trimming
io_size to valid in-EOF data while avoiding the underflow.
Fixes: 51d20d1dacbe ("iomap: fix zero padding data issue in concurrent append writes")
Signed-off-by: Morduan Zang <zhangdandan@uniontech.com>
---
fs/iomap/ioend.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c
index acf3cf98b23a..0c391a66db6f 100644
--- a/fs/iomap/ioend.c
+++ b/fs/iomap/ioend.c
@@ -297,8 +297,12 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
* appending writes.
*/
ioend->io_size += map_len;
- if (ioend->io_offset + ioend->io_size > end_pos)
- ioend->io_size = end_pos - ioend->io_offset;
+ if (ioend->io_offset + ioend->io_size > end_pos) {
+ if (end_pos > ioend->io_offset)
+ ioend->io_size = end_pos - ioend->io_offset;
+ else
+ ioend->io_size = 0;
+ }
wbc_account_cgroup_owner(wpc->wbc, folio, map_len);
return map_len;
--
2.50.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow
2026-06-18 5:38 [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow Morduan Zang
@ 2026-06-18 9:08 ` Christoph Hellwig
2026-06-18 11:03 ` Morduan Zang
2026-06-19 8:25 ` Christian Brauner
1 sibling, 1 reply; 5+ messages in thread
From: Christoph Hellwig @ 2026-06-18 9:08 UTC (permalink / raw)
To: Morduan Zang; +Cc: brauner, linux-fsdevel, linux-xfs, djwong
On Thu, Jun 18, 2026 at 01:38:20PM +0800, Morduan Zang wrote:
> However, ioend can be created before a concurrent truncate shrinks
> the file. In that case, end_pos can move below ioend->io_offset
> before the trim happens. The subtraction then becomes negative, but
> the result is stored in size_t io_size, causing an unsigned wrap to
> a huge value.
>
> A wrapped io_size can mislead append detection and corrupt
> completion-time size handling, since filesystem end_io paths consume
> io_size for decisions such as on-disk EOF updates and unwritten/COW
> completion ranges.
Do you have examples for this? I.e. did you hit this with a workload,
or did you just look over the code for issues?
> + if (ioend->io_offset + ioend->io_size > end_pos) {
> + if (end_pos > ioend->io_offset)
> + ioend->io_size = end_pos - ioend->io_offset;
> + else
> + ioend->io_size = 0;
> + }
I find this a bit hard to read due to different paramter ordering,
i.e. why not:
if (ioend->io_offset + ioend->io_size > end_pos) {
if (ioend->io_offset >= end_pos)
ioend->io_size = 0;
else
ioend->io_size = end_pos - ioend->io_offset;
}
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow
2026-06-18 9:08 ` Christoph Hellwig
@ 2026-06-18 11:03 ` Morduan Zang
2026-06-18 13:36 ` Christoph Hellwig
0 siblings, 1 reply; 5+ messages in thread
From: Morduan Zang @ 2026-06-18 11:03 UTC (permalink / raw)
To: hch; +Cc: brauner, djwong, linux-fsdevel, linux-xfs, zhangdandan
On Thu, Jun 18, 2026 at 01:38:20PM +0800, Christian Brauner wrote:
> Do you have examples for this? I.e. did you hit this with a workload,
> or did you just look over the code for issues?
No, I do not have a workload reproducer. I noticed this while reviewing
the EOF trim in 51d20d1dacbe for backport — our static analysis flagged
that end_pos - ioend->io_offset is assigned to size_t without ensuring
end_pos >= ioend->io_offset.
I have not been able to trigger this in testing yet, so I do not want to
overstate the practical impact. That said, once the trim path is taken
with end_pos <= io_offset, the current code clearly wraps io_size, which
seems wrong relative to the intent of that commit (io_size should reflect
valid in-EOF data, i.e. zero in that case). Filesystem completion paths
also use io_size for range decisions beyond a simple EOF update.
If you consider this path unreachable in practice I am happy to drop the
patch. Otherwise, the guard itself is small and only affects the trim
branch — I can send a v2 with your suggested ordering if you think it is
worth hardening even without a reproducer.
> I find this a bit hard to read due to different paramter ordering,
> i.e. why not:
>
> if (ioend->io_offset + ioend->io_size > end_pos) {
> if (ioend->io_offset >= end_pos)
> ioend->io_size = 0;
> else
> ioend->io_size = end_pos - ioend->io_offset;
> }
If you are fine with this change, I will send a v2 with this ordering to
improve code quality.
Thanks,
Morduan Zang
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow
2026-06-18 11:03 ` Morduan Zang
@ 2026-06-18 13:36 ` Christoph Hellwig
0 siblings, 0 replies; 5+ messages in thread
From: Christoph Hellwig @ 2026-06-18 13:36 UTC (permalink / raw)
To: Morduan Zang; +Cc: hch, brauner, djwong, linux-fsdevel, linux-xfs
On Thu, Jun 18, 2026 at 07:03:07PM +0800, Morduan Zang wrote:
> No, I do not have a workload reproducer. I noticed this while reviewing
> the EOF trim in 51d20d1dacbe for backport — our static analysis flagged
> that end_pos - ioend->io_offset is assigned to size_t without ensuring
> end_pos >= ioend->io_offset.
Ok, makes sense.
> If you consider this path unreachable in practice I am happy to drop the
> patch. Otherwise, the guard itself is small and only affects the trim
> branch — I can send a v2 with your suggested ordering if you think it is
> worth hardening even without a reproducer.
I don't think it's impossible. Just curious where this change comes
from and hoping for a reproducer if we can come up with one.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow
2026-06-18 5:38 [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow Morduan Zang
2026-06-18 9:08 ` Christoph Hellwig
@ 2026-06-19 8:25 ` Christian Brauner
1 sibling, 0 replies; 5+ messages in thread
From: Christian Brauner @ 2026-06-19 8:25 UTC (permalink / raw)
To: Morduan Zang; +Cc: linux-fsdevel, linux-xfs, djwong
On Thu, 18 Jun 2026 13:38:20 +0800, Morduan Zang wrote:
> iomap: guard io_size EOF trim against concurrent truncate underflow
Applied to the vfs.fixes branch of the vfs/vfs.git tree.
Patches in the vfs.fixes branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs.fixes
[1/1] iomap: guard io_size EOF trim against concurrent truncate underflow
https://git.kernel.org/vfs/vfs/c/2cd97101983e
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-19 8:25 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18 5:38 [PATCH] iomap: guard io_size EOF trim against concurrent truncate underflow Morduan Zang
2026-06-18 9:08 ` Christoph Hellwig
2026-06-18 11:03 ` Morduan Zang
2026-06-18 13:36 ` Christoph Hellwig
2026-06-19 8:25 ` Christian Brauner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox