mirror of https://github.com/torvalds/linux.git
iomap: fix iomap_read_end() for already uptodate folios
There are some cases where when iomap_read_end() is called, the folio may already have been marked uptodate. For example, if the iomap block needed zeroing, then the folio may have been marked uptodate after the zeroing. iomap_read_end() should unlock the folio instead of calling folio_end_read(), which is how these cases were handled prior to commitf8eaf79406("iomap: simplify ->read_folio_range() error handling for reads"). Calling folio_end_read() on an uptodate folio leads to buggy behavior where marking an already uptodate folio as uptodate will XOR it to be marked nonuptodate. Fixes:f8eaf79406("iomap: simplify ->read_folio_range() error handling for reads") Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Link: https://patch.msgid.link/20251118211111.1027272-2-joannelkoong@gmail.com Tested-by: Matthew Wilcox (Oracle) <willy@infradead.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Reported-by: Matthew Wilcox (Oracle) <willy@infradead.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
5ec58e6acd
commit
d7ff85d4b8
|
|
@ -458,25 +458,26 @@ static void iomap_read_end(struct folio *folio, size_t bytes_submitted)
|
||||||
spin_lock_irq(&ifs->state_lock);
|
spin_lock_irq(&ifs->state_lock);
|
||||||
if (!ifs->read_bytes_pending) {
|
if (!ifs->read_bytes_pending) {
|
||||||
WARN_ON_ONCE(bytes_submitted);
|
WARN_ON_ONCE(bytes_submitted);
|
||||||
end_read = true;
|
spin_unlock_irq(&ifs->state_lock);
|
||||||
} else {
|
folio_unlock(folio);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subtract any bytes that were initially accounted to
|
* Subtract any bytes that were initially accounted to
|
||||||
* read_bytes_pending but skipped for IO. The +1
|
* read_bytes_pending but skipped for IO. The +1 accounts for
|
||||||
* accounts for the bias we added in iomap_read_init().
|
* the bias we added in iomap_read_init().
|
||||||
*/
|
*/
|
||||||
size_t bytes_not_submitted = folio_size(folio) + 1 -
|
ifs->read_bytes_pending -=
|
||||||
bytes_submitted;
|
(folio_size(folio) + 1 - bytes_submitted);
|
||||||
ifs->read_bytes_pending -= bytes_not_submitted;
|
|
||||||
/*
|
/*
|
||||||
* If !ifs->read_bytes_pending, this means all pending
|
* If !ifs->read_bytes_pending, this means all pending reads by
|
||||||
* reads by the IO helper have already completed, which
|
* the IO helper have already completed, which means we need to
|
||||||
* means we need to end the folio read here. If
|
* end the folio read here. If ifs->read_bytes_pending != 0,
|
||||||
* ifs->read_bytes_pending != 0, the IO helper will end
|
* the IO helper will end the folio read.
|
||||||
* the folio read.
|
|
||||||
*/
|
*/
|
||||||
end_read = !ifs->read_bytes_pending;
|
end_read = !ifs->read_bytes_pending;
|
||||||
}
|
|
||||||
if (end_read)
|
if (end_read)
|
||||||
uptodate = ifs_is_fully_uptodate(folio, ifs);
|
uptodate = ifs_is_fully_uptodate(folio, ifs);
|
||||||
spin_unlock_irq(&ifs->state_lock);
|
spin_unlock_irq(&ifs->state_lock);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue