summaryrefslogtreecommitdiff
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-10-08 13:50:47 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-12-15 17:28:49 -0800
commit9d8891744e56321c708ed8597902b2ce616d3f08 (patch)
tree370b1000222e021731532073f39083588b0e359f /fs/xfs
parentc71e3a53c4e2f739646e8dbde32a608be9c4bfa2 (diff)
xfs: ignore stale buffers when scanning the buffer cache
After an online repair, we need to invalidate buffers representing the blocks from the old metadata that we're replacing. It's possible that parts of a tree that were previously cached in memory are no longer accessible due to media failure or other corruption on interior nodes, so repair figures out the old blocks from the reverse mapping data and scans the buffer cache directly. Unfortunately, the current buffer cache code triggers asserts if the rhashtable lookup finds a non-stale buffer of a different length than the key we searched for. For regular operation this is desirable, but for this repair procedure, we don't care since we're going to forcibly stale the buffer anyway. Add an internal lookup flag to avoid the assert. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/scrub/repair.c2
-rw-r--r--fs/xfs/xfs_buf.c6
-rw-r--r--fs/xfs/xfs_buf.h11
3 files changed, 17 insertions, 2 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index a6ca39e1d5c4..3d62feaee72d 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -511,7 +511,7 @@ xrep_block_reap_binval(
*/
bp = xfs_buf_incore(sc->mp->m_ddev_targp,
XFS_FSB_TO_DADDR(sc->mp, fsbno),
- XFS_FSB_TO_BB(sc->mp, 1), 0);
+ XFS_FSB_TO_BB(sc->mp, 1), XBF_BCACHE_SCAN);
if (!bp)
return;
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 631c5a61d89b..e6f3cb9ef55a 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -471,7 +471,8 @@ _xfs_buf_obj_cmp(
* reallocating a busy extent. Skip this buffer and
* continue searching for an exact match.
*/
- ASSERT(bp->b_flags & XBF_STALE);
+ if (!(map->bm_flags & XBM_IGNORE_LENGTH_MISMATCH))
+ ASSERT(bp->b_flags & XBF_STALE);
return 1;
}
return 0;
@@ -535,6 +536,9 @@ xfs_buf_find(
xfs_daddr_t eofs;
int i;
+ if (flags & XBF_BCACHE_SCAN)
+ cmap.bm_flags |= XBM_IGNORE_LENGTH_MISMATCH;
+
*found_bp = NULL;
for (i = 0; i < nmaps; i++)
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index 6b0200b8007d..457562bd7fc6 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -42,6 +42,12 @@ struct xfs_buf;
#define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */
/* flags used only as arguments to access routines */
+
+/*
+ * We're scanning the buffer cache; do not warn about lookup mismatches.
+ * Only online repair should use this.
+ */
+#define XBF_BCACHE_SCAN (1 << 29)
#define XBF_TRYLOCK (1 << 30)/* lock requested, but do not wait */
#define XBF_UNMAPPED (1 << 31)/* do not map the buffer */
@@ -63,6 +69,7 @@ typedef unsigned int xfs_buf_flags_t;
{ _XBF_KMEM, "KMEM" }, \
{ _XBF_DELWRI_Q, "DELWRI_Q" }, \
/* The following interface flags should never be set */ \
+ { XBF_BCACHE_SCAN, "BCACHE_SCAN" }, \
{ XBF_TRYLOCK, "TRYLOCK" }, \
{ XBF_UNMAPPED, "UNMAPPED" }
@@ -108,8 +115,12 @@ typedef struct xfs_buftarg {
struct xfs_buf_map {
xfs_daddr_t bm_bn; /* block number for I/O */
int bm_len; /* size of I/O */
+ unsigned int bm_flags;
};
+/* Don't complain about live buffers with the wrong length during lookup. */
+#define XBM_IGNORE_LENGTH_MISMATCH (1U << 0)
+
#define DEFINE_SINGLE_BUF_MAP(map, blkno, numblk) \
struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) };