diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-01-05 17:47:08 -0800 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-03-25 17:08:51 -0700 |
commit | 52f9e4d68f1b9238c33df80bd1f80832723b42b5 (patch) | |
tree | e3ac4e2a8ed4761fbd293125afe96142a1313710 | |
parent | d3c926dd003dff968c261db525c69867f68073a5 (diff) |
xfs: cross-reference chceks with the rt refcount btree
Use the realtime refcount btree to cross-reference other data
structures.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r-- | fs/xfs/scrub/bmap.c | 12 | ||||
-rw-r--r-- | fs/xfs/scrub/rtbitmap.c | 1 | ||||
-rw-r--r-- | fs/xfs/scrub/rtrefcount.c | 66 | ||||
-rw-r--r-- | fs/xfs/scrub/rtrmap.c | 37 | ||||
-rw-r--r-- | fs/xfs/scrub/scrub.h | 6 |
5 files changed, 122 insertions, 0 deletions
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index 448735d9213d..792eb38ecae1 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -341,6 +341,18 @@ xchk_bmap_rt_iextent_xref( xchk_xref_is_used_rt_space(info->sc, irec->br_startblock, irec->br_blockcount); xchk_bmap_xref_rmap(info, irec, irec->br_startblock); + switch (info->whichfork) { + case XFS_DATA_FORK: + if (xfs_is_reflink_inode(info->sc->ip)) + break; + xchk_xref_is_not_shared_rt(info->sc, irec->br_startblock, + irec->br_blockcount); + break; + case XFS_COW_FORK: + xchk_xref_is_rt_cow_staging(info->sc, irec->br_startblock, + irec->br_blockcount); + break; + } xchk_rt_btcur_free(&info->sc->sr); xchk_rt_unlock(info->sc, &info->sc->sr); diff --git a/fs/xfs/scrub/rtbitmap.c b/fs/xfs/scrub/rtbitmap.c index ef29b675f0e1..9762d6956d69 100644 --- a/fs/xfs/scrub/rtbitmap.c +++ b/fs/xfs/scrub/rtbitmap.c @@ -88,6 +88,7 @@ xchk_rtbitmap_xref( return; xchk_xref_has_no_rt_owner(sc, startblock, blockcount); + xchk_xref_is_not_shared_rt(sc, startblock, blockcount); } /* Scrub a free extent record from the realtime bitmap. */ diff --git a/fs/xfs/scrub/rtrefcount.c b/fs/xfs/scrub/rtrefcount.c index e5de169cb8e6..b6757cb140d3 100644 --- a/fs/xfs/scrub/rtrefcount.c +++ b/fs/xfs/scrub/rtrefcount.c @@ -441,3 +441,69 @@ xchk_rtrefcountbt( out_unlock: return error; } + +/* xref check that a cow staging extent is marked in the rtrefcountbt. */ +void +xchk_xref_is_rt_cow_staging( + struct xfs_scrub *sc, + xfs_rtblock_t bno, + xfs_filblks_t len) +{ + struct xfs_refcount_irec rc; + bool has_cowflag; + int has_refcount; + int error; + + if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm)) + return; + + /* Find the CoW staging extent. */ + error = xfs_refcount_lookup_le(sc->sr.refc_cur, + bno + XFS_RTREFC_COW_START, &has_refcount); + if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) + return; + if (!has_refcount) { + xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); + return; + } + + error = xfs_refcount_get_rec(sc->sr.refc_cur, &rc, &has_refcount); + if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) + return; + if (!has_refcount) { + xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); + return; + } + + /* CoW flag must be set, refcount must be 1. */ + has_cowflag = (rc.rc_startblock & XFS_RTREFC_COW_START); + if (!has_cowflag || rc.rc_refcount != 1) + xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); + + /* Must be at least as long as what was passed in */ + if (rc.rc_blockcount < len) + xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); +} + +/* + * xref check that the extent is not shared. Only file data blocks + * can have multiple owners. + */ +void +xchk_xref_is_not_shared_rt( + struct xfs_scrub *sc, + xfs_rtblock_t bno, + xfs_filblks_t len) +{ + bool shared; + int error; + + if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm)) + return; + + error = xfs_refcount_has_record(sc->sr.refc_cur, bno, len, &shared); + if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) + return; + if (shared) + xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); +} diff --git a/fs/xfs/scrub/rtrmap.c b/fs/xfs/scrub/rtrmap.c index 346548bb21f1..c079fcade217 100644 --- a/fs/xfs/scrub/rtrmap.c +++ b/fs/xfs/scrub/rtrmap.c @@ -20,6 +20,7 @@ #include "xfs_rtrmap_btree.h" #include "xfs_inode.h" #include "xfs_rtalloc.h" +#include "xfs_refcount.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h" @@ -63,6 +64,37 @@ xchk_setup_rtrmapbt( /* Realtime reverse mapping. */ +/* Cross-reference a rmap against the refcount btree. */ +STATIC void +xchk_rtrmapbt_xref_rtrefc( + struct xfs_scrub *sc, + struct xfs_rmap_irec *irec) +{ + xfs_rtblock_t fbno; + xfs_filblks_t flen; + bool non_inode; + bool is_bmbt; + bool is_attr; + bool is_unwritten; + int error; + + if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm)) + return; + + non_inode = XFS_RMAP_NON_INODE_OWNER(irec->rm_owner); + is_bmbt = irec->rm_flags & XFS_RMAP_BMBT_BLOCK; + is_attr = irec->rm_flags & XFS_RMAP_ATTR_FORK; + is_unwritten = irec->rm_flags & XFS_RMAP_UNWRITTEN; + + /* If this is shared, must be a data fork extent. */ + error = xfs_refcount_find_shared(sc->sr.refc_cur, irec->rm_startblock, + irec->rm_blockcount, &fbno, &flen, false); + if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur)) + return; + if (flen != 0 && (non_inode || is_attr || is_bmbt || is_unwritten)) + xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0); +} + /* Cross-reference with other metadata. */ STATIC void xchk_rtrmapbt_xref( @@ -74,6 +106,11 @@ xchk_rtrmapbt_xref( xchk_xref_is_used_rt_space(sc, irec->rm_startblock, irec->rm_blockcount); + if (irec->rm_owner == XFS_RMAP_OWN_COW) + xchk_xref_is_cow_staging(sc, irec->rm_startblock, + irec->rm_blockcount); + else + xchk_rtrmapbt_xref_rtrefc(sc, irec); } /* Scrub a realtime rmapbt record. */ diff --git a/fs/xfs/scrub/scrub.h b/fs/xfs/scrub/scrub.h index 2e19fa3ae73a..314d52fcf0fc 100644 --- a/fs/xfs/scrub/scrub.h +++ b/fs/xfs/scrub/scrub.h @@ -214,9 +214,15 @@ void xchk_xref_is_used_rt_space(struct xfs_scrub *sc, xfs_rtblock_t rtbno, xfs_extlen_t len); void xchk_xref_has_no_rt_owner(struct xfs_scrub *sc, xfs_rtblock_t rtbno, xfs_filblks_t len); +void xchk_xref_is_rt_cow_staging(struct xfs_scrub *sc, xfs_rtblock_t bno, + xfs_filblks_t len); +void xchk_xref_is_not_shared_rt(struct xfs_scrub *sc, xfs_rtblock_t bno, + xfs_filblks_t len); #else # define xchk_xref_is_used_rt_space(sc, rtbno, len) do { } while (0) # define xchk_xref_has_no_rt_owner(sc, rtbno, len) do { } while (0) +# define xchk_xref_is_rt_cow_staging(sc, bno, len) do { } while (0) +# define xchk_xref_is_not_shared_rt(sc, bno, len) do { } while (0) #endif struct xchk_fscounters { |