mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
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: 51d20d1dac ("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>
This commit is contained in:
committed by
Christian Brauner
parent
597a7bc763
commit
55ec50d046
@@ -298,8 +298,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 (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;
|
||||
|
||||
Reference in New Issue
Block a user