summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub/rtrefcount.c
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 11:19:44 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-10-22 16:41:10 -0700
commit61868eecf1989c1eda421d596d17c27317237e7a (patch)
tree0633e90ecd264383c5bf968635a1686690332524 /fs/xfs/scrub/rtrefcount.c
parent732f6fe3d46895365dc7040d5098ff55929cd6d5 (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>
Diffstat (limited to 'fs/xfs/scrub/rtrefcount.c')
-rw-r--r--fs/xfs/scrub/rtrefcount.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/fs/xfs/scrub/rtrefcount.c b/fs/xfs/scrub/rtrefcount.c
index 21b74b9923de..ae0897b081ab 100644
--- a/fs/xfs/scrub/rtrefcount.c
+++ b/fs/xfs/scrub/rtrefcount.c
@@ -447,3 +447,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);
+}