diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-10-08 13:50:47 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-10-22 16:40:34 -0700 |
commit | 8582bdcecd5fa790e51f0dfa8b285ef2e3d2a165 (patch) | |
tree | ce56400acc4c90c9d57782ad4bc7469c42732a39 | |
parent | ffa50cee5217d9feba3b4b6777b17b6ced684e66 (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.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_buf.c | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_buf.h | 6 |
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) }; |