diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 10:40:16 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-10-22 16:40:33 -0700 |
commit | 5a14297eca8eda4a222610bb32279704d0ec30ef (patch) | |
tree | fd4eebb124d7ff366dd8bed97963c36257c94d88 | |
parent | 40fe312d0cf9d472aa68527597ba7b2d84a4fef7 (diff) |
xfs: only invalidate blocks if we're going to free them
When we're discarding old btree blocks after a repair, only invalidate
the buffers for the ones that we're freeing -- if the metadata was
crosslinked with another data structure, we don't want to touch it.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r-- | fs/xfs/scrub/repair.c | 78 | ||||
-rw-r--r-- | fs/xfs/scrub/repair.h | 1 |
2 files changed, 35 insertions, 44 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 1e7b6b209ee8..2f16b6900f5e 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -434,44 +434,6 @@ xrep_init_btblock( * buffers associated with @bitmap. */ -/* - * Invalidate buffers for per-AG btree blocks we're dumping. This function - * is not intended for use with file data repairs; we have bunmapi for that. - */ -int -xrep_invalidate_blocks( - struct xfs_scrub *sc, - struct xbitmap *bitmap) -{ - struct xbitmap_range *bmr; - struct xbitmap_range *n; - struct xfs_buf *bp; - xfs_fsblock_t fsbno; - - /* - * For each block in each extent, see if there's an incore buffer for - * exactly that block; if so, invalidate it. The buffer cache only - * lets us look for one buffer at a time, so we have to look one block - * at a time. Avoid invalidating AG headers and post-EOFS blocks - * because we never own those; and if we can't TRYLOCK the buffer we - * assume it's owned by someone else. - */ - for_each_xbitmap_block(fsbno, bmr, n, bitmap) { - /* Skip AG headers and post-EOFS blocks */ - if (!xfs_verify_fsbno(sc->mp, fsbno)) - continue; - 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); - if (bp) { - xfs_trans_bjoin(sc->tp, bp); - xfs_trans_binval(sc->tp, bp); - } - } - - return 0; -} - /* Ensure the freelist is the correct size. */ int xrep_fix_freelist( @@ -526,6 +488,33 @@ xrep_put_freelist( return 0; } +/* Try to invalidate the incore buffer for a block that we're about to free. */ +STATIC void +xrep_reap_invalidate_block( + struct xfs_scrub *sc, + xfs_fsblock_t fsbno) +{ + struct xfs_buf *bp; + + /* + * If there's an incore buffer for exactly this block, invalidate it. + * Avoid invalidating AG headers and post-EOFS blocks because we never + * own those; and if we can't TRYLOCK the buffer we assume it's owned + * by someone else. + */ + if (!xfs_verify_fsbno(sc->mp, fsbno)) + return; + + 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); + if (!bp) + return; + + xfs_trans_bjoin(sc->tp, bp); + xfs_trans_binval(sc->tp, bp); +} + /* Dispose of a single block. */ STATIC int xrep_reap_block( @@ -577,13 +566,16 @@ xrep_reap_block( * blow on writeout, the filesystem will shut down, and the admin gets * to run xfs_repair. */ - if (has_other_rmap) - error = xfs_rmap_free(sc->tp, agf_bp, sc->sa.pag, agbno, - 1, oinfo); - else if (resv == XFS_AG_RESV_AGFL) + if (has_other_rmap) { + error = xfs_rmap_free(sc->tp, agf_bp, sc->sa.pag, agbno, 1, + oinfo); + } else if (resv == XFS_AG_RESV_AGFL) { + xrep_reap_invalidate_block(sc, fsbno); error = xrep_put_freelist(sc, agbno); - else + } else { + xrep_reap_invalidate_block(sc, fsbno); error = xfs_free_extent(sc->tp, fsbno, 1, oinfo, resv); + } if (agf_bp != sc->sa.agf_bp) xfs_trans_brelse(sc->tp, agf_bp); if (error) diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h index 3bb152d52a07..98019b21fa7b 100644 --- a/fs/xfs/scrub/repair.h +++ b/fs/xfs/scrub/repair.h @@ -33,7 +33,6 @@ int xrep_init_btblock(struct xfs_scrub *sc, xfs_fsblock_t fsb, struct xbitmap; int xrep_fix_freelist(struct xfs_scrub *sc, bool can_shrink); -int xrep_invalidate_blocks(struct xfs_scrub *sc, struct xbitmap *btlist); int xrep_reap_extents(struct xfs_scrub *sc, struct xbitmap *exlist, const struct xfs_owner_info *oinfo, enum xfs_ag_resv_type type); |