[PATCH 16/21] xfs: improve detection of lost xfile contents

Christoph Hellwig
2024-01-26T13:30:17Z

From: "Darrick J. Wong" <djwong@kernel.org>

shmem files are weird animals with respect to figuring out if we've lost
any data. The memory failure code can set HWPoison on a page, but it
also sets writeback errors on the file mapping. Replace the twisty
multi-line if logic with a single helper that looks in all the places
that I know of where memory errors can show up.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/xfs/scrub/xfile.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
index 077f9ce6e81409..2d802c20a8ddfe 100644
--- a/fs/xfs/scrub/xfile.c
+++ b/fs/xfs/scrub/xfile.c
@@ -99,6 +99,31 @@ xfile_destroy(
kfree(xf);
}

+/* Has this file lost any of the data stored in it? */
+static inline bool
+xfile_has_lost_data(
+ struct inode *inode,
+ struct folio *folio)
+{
+ struct address_space *mapping = inode->i_mapping;
+
+ /* This folio itself has been poisoned. */
+ if (folio_test_hwpoison(folio))
+ return true;
+
+ /* A base page under this large folio has been poisoned. */
+ if (folio_test_large(folio) && folio_test_has_hwpoisoned(folio))
+ return true;
+
+ /* Data loss has occurred anywhere in this shmem file. */
+ if (test_bit(AS_EIO, &mapping->flags))
+ return true;
+ if (filemap_check_wb_err(mapping, 0))
+ return true;
+
+ return false;
+}
+
/*
* Load an object. Since we're treating this file as "memory", any error or
* short IO is treated as a failure to allocate memory.
@@ -138,9 +163,7 @@ xfile_load(
PAGE_SIZE - offset_in_page(pos));
memset(buf, 0, len);
} else {
- if (folio_test_hwpoison(folio) ||
- (folio_test_large(folio) &&
- folio_test_has_hwpoisoned(folio))) {
+ if (xfile_has_lost_data(inode, folio)) {
folio_unlock(folio);
folio_put(folio);
break;
@@ -201,9 +224,7 @@ xfile_store(
if (shmem_get_folio(inode, pos >> PAGE_SHIFT, &folio,
SGP_CACHE) < 0)
break;
- if (folio_test_hwpoison(folio) ||
- (folio_test_large(folio) &&
- folio_test_has_hwpoisoned(folio))) {
+ if (xfile_has_lost_data(inode, folio)) {
folio_unlock(folio);
folio_put(folio);
break;
--
2.39.2