Skip to content

Commit debc1a4

Browse files
joannekoongbrauner
authored andcommitted
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: b2f35ac ("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>
1 parent 1004714 commit debc1a4

1 file changed

Lines changed: 12 additions & 3 deletions

File tree

fs/iomap/buffered-io.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,27 @@ static void iomap_set_range_uptodate(struct folio *folio, size_t off,
8080
{
8181
struct iomap_folio_state *ifs = folio->private;
8282
unsigned long flags;
83-
bool uptodate = true;
83+
bool mark_uptodate = true;
8484

8585
if (folio_test_uptodate(folio))
8686
return;
8787

8888
if (ifs) {
8989
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;
91100
spin_unlock_irqrestore(&ifs->state_lock, flags);
92101
}
93102

94-
if (uptodate)
103+
if (mark_uptodate)
95104
folio_mark_uptodate(folio);
96105
}
97106

0 commit comments

Comments
 (0)