diff options
| author | Morduan Zang <zhangdandan@uniontech.com> | 2026-06-24 14:26:22 +0800 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-07-01 15:26:27 +0200 |
| commit | 55ec50d046c03b3724741957f7b007856e36dbe7 (patch) | |
| tree | 98618f03cf56bc16fed23c3f382bbb680ceecc80 /fs | |
| parent | 597a7bc7630035580e941a548cb646618c1c5933 (diff) | |
| download | linux-55ec50d046c03b3724741957f7b007856e36dbe7.tar.gz linux-55ec50d046c03b3724741957f7b007856e36dbe7.zip | |
iomap: guard io_size EOF trim against concurrent truncate underflow
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, if end_pos ends up below ioend->io_offset, the subtraction
becomes negative and is stored in size_t io_size, causing an unsigned
wrap to a huge value. This can happen when writeback continues past
byte-level EOF up to a block-aligned range, or when a concurrent
truncate shrinks the file after end_pos was sampled in
iomap_writeback_handle_eof().
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")
Suggested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Morduan Zang <zhangdandan@uniontech.com>
Link: https://patch.msgid.link/9E38E2659B47DC2A+20260624062622.337469-1-zhangdandan@uniontech.com
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/iomap/ioend.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c index f7c3e0c70fd7..0565328764c1 100644 --- a/fs/iomap/ioend.c +++ b/fs/iomap/ioend.c @@ -298,8 +298,12 @@ new_ioend: * 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 (ioend->io_offset >= end_pos) + ioend->io_size = 0; + else + ioend->io_size = end_pos - ioend->io_offset; + } wbc_account_cgroup_owner(wpc->wbc, folio, map_len); return map_len; |
