btrfs: retry verity reads for not-uptodate Merkle folios

btrfs_read_merkle_tree_page() can find a folio in the mapping that is not
uptodate.  After taking the folio lock, the current code treats that state
as a read error and returns -EIO.

That can make a previous transient read failure sticky.  If the failed read
left a not-uptodate folio in the mapping, later callers find that folio and
fail instead of retrying the read.

Keep the existing page-cache insertion and locking order, but retry the
Merkle item read when a not-uptodate folio is found in the mapping.  Also
unlock the folio when read_key_bytes() fails so that a later caller can
lock it and retry the read.

Fixes: 06ed09351b ("btrfs: convert btrfs_read_merkle_tree_page() to use a folio")
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Yichong Chen
2026-08-07 19:17:18 +02:00
committed by David Sterba
parent d34a3a8ba6
commit 8cc569696d
+11 -5
View File
@@ -720,14 +720,18 @@ again:
goto out;
folio_lock(folio);
/* If it's not uptodate after we have the lock, we got a read error. */
if (!folio_test_uptodate(folio)) {
/* Folio was truncated from mapping. */
if (!folio->mapping) {
folio_unlock(folio);
folio_put(folio);
return ERR_PTR(-EIO);
goto again;
}
folio_unlock(folio);
goto out;
/* Another reader may have filled the folio while we waited. */
if (folio_test_uptodate(folio)) {
folio_unlock(folio);
goto out;
}
goto read_folio;
}
folio = filemap_alloc_folio(mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS),
@@ -744,6 +748,7 @@ again:
return ERR_PTR(ret);
}
read_folio:
/*
* Merkle item keys are indexed from byte 0 in the merkle tree.
* They have the form:
@@ -753,6 +758,7 @@ again:
ret = read_key_bytes(BTRFS_I(inode), BTRFS_VERITY_MERKLE_ITEM_KEY, off,
folio_address(folio), PAGE_SIZE, folio);
if (ret < 0) {
folio_unlock(folio);
folio_put(folio);
return ERR_PTR(ret);
}