summaryrefslogtreecommitdiff
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-10-22 16:40:34 -0700
commit8582bdcecd5fa790e51f0dfa8b285ef2e3d2a165 (patch)
treece56400acc4c90c9d57782ad4bc7469c42732a39
parentffa50cee5217d9feba3b4b6777b17b6ced684e66 (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>
-rw-r--r--fs/xfs/scrub/repair.c3
-rw-r--r--fs/xfs/xfs_buf.c6
-rw-r--r--fs/xfs/xfs_buf.h6
3 files changed, 13 insertions, 2 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 066db40d746c..5a6933f41c71 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -508,7 +508,8 @@ xrep_reap_invalidate_block(
bp = xfs_buf_incore(sc->mp->m_ddev_targp,
XFS_FSB_TO_DADDR(sc->mp, fsbno),
- XFS_FSB_TO_BB(sc->mp, 1), XBF_TRYLOCK);
+ XFS_FSB_TO_BB(sc->mp, 1),
+ XBF_TRYLOCK | _XBF_IGNORE_STALE);
if (!bp)
return;
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 5fa6cd947dd4..ea1f5177eb7a 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_STALE))
+ 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_IGNORE_STALE)
+ cmap.bm_flags |= XBM_IGNORE_STALE;
+
*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..262cf378d65b 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -42,6 +42,7 @@ struct xfs_buf;
#define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */
/* flags used only as arguments to access routines */
+#define _XBF_IGNORE_STALE (1 << 29)/* ignore stale buffers */
#define XBF_TRYLOCK (1 << 30)/* lock requested, but do not wait */
#define XBF_UNMAPPED (1 << 31)/* do not map the buffer */
@@ -63,6 +64,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_IGNORE_STALE, "IGNORE_STALE" }, \
{ XBF_TRYLOCK, "TRYLOCK" }, \
{ XBF_UNMAPPED, "UNMAPPED" }
@@ -108,8 +110,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;
};
+/* Ignore stale buffers while scanning the buffer cache. */
+#define XBM_IGNORE_STALE (1U << 0)
+
#define DEFINE_SINGLE_BUF_MAP(map, blkno, numblk) \
struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) };