Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iomap: don't mark folio uptodate if read IO has bytes pending

If a folio has ifs metadata attached to it and the folio is partially
read in through an async IO helper with the rest of it then being read
in through post-EOF zeroing or as inline data, and the helper
successfully finishes the read first, then post-EOF zeroing / reading
inline will mark the folio as uptodate in iomap_set_range_uptodate().

This is a problem because when the read completion path later calls
iomap_read_end(), it will call folio_end_read(), which sets the uptodate
bit using XOR semantics. Calling folio_end_read() on a folio that was
already marked uptodate clears the uptodate bit.

Fix this by not marking the folio as uptodate if the read IO has bytes
pending. The folio uptodate state will be set in the read completion
path through iomap_end_read() -> folio_end_read().

Reported-by: Wei Gao <wegao@suse.com>
Suggested-by: Sasha Levin <sashal@kernel.org>
Tested-by: Wei Gao <wegao@suse.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Cc: stable@vger.kernel.org # v6.19
Link: https://lore.kernel.org/linux-fsdevel/aYbmy8JdgXwsGaPP@autotest-wegao.qe.prg2.suse.org/
Fixes: b2f35ac4146d ("iomap: add caller-provided callbacks for read and readahead")
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Link: https://patch.msgid.link/20260303233420.874231-2-joannelkoong@gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Joanne Koong and committed by
Christian Brauner
debc1a49 10047142

+12 -3
+12 -3
fs/iomap/buffered-io.c
··· 80 80 { 81 81 struct iomap_folio_state *ifs = folio->private; 82 82 unsigned long flags; 83 - bool uptodate = true; 83 + bool mark_uptodate = true; 84 84 85 85 if (folio_test_uptodate(folio)) 86 86 return; 87 87 88 88 if (ifs) { 89 89 spin_lock_irqsave(&ifs->state_lock, flags); 90 - uptodate = ifs_set_range_uptodate(folio, ifs, off, len); 90 + /* 91 + * If a read with bytes pending is in progress, we must not call 92 + * folio_mark_uptodate(). The read completion path 93 + * (iomap_read_end()) will call folio_end_read(), which uses XOR 94 + * semantics to set the uptodate bit. If we set it here, the XOR 95 + * in folio_end_read() will clear it, leaving the folio not 96 + * uptodate. 97 + */ 98 + mark_uptodate = ifs_set_range_uptodate(folio, ifs, off, len) && 99 + !ifs->read_bytes_pending; 91 100 spin_unlock_irqrestore(&ifs->state_lock, flags); 92 101 } 93 102 94 - if (uptodate) 103 + if (mark_uptodate) 95 104 folio_mark_uptodate(folio); 96 105 } 97 106