]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: cross-reference the realtime rmapbt
authorDarrick J. Wong <djwong@kernel.org>
Mon, 23 Sep 2024 20:42:10 +0000 (13:42 -0700)
committerChristoph Hellwig <hch@lst.de>
Wed, 9 Oct 2024 13:55:47 +0000 (15:55 +0200)
Teach the data fork and realtime bitmap scrubbers to cross-reference
information with the realtime rmap btree.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/scrub/bmap.c
fs/xfs/scrub/rgsuper.c
fs/xfs/scrub/rtbitmap.c
fs/xfs/scrub/rtbitmap.h
fs/xfs/scrub/rtrmap.c
fs/xfs/scrub/scrub.h

index e80cde3bea082823ad292a7ce913b2abd983bf18..4f45071f0d1ca297800b65bf2767c763c71e99ad 100644 (file)
@@ -143,15 +143,22 @@ static inline bool
 xchk_bmap_get_rmap(
        struct xchk_bmap_info   *info,
        struct xfs_bmbt_irec    *irec,
-       xfs_agblock_t           agbno,
+       xfs_agblock_t           bno,
        uint64_t                owner,
        struct xfs_rmap_irec    *rmap)
 {
+       struct xfs_btree_cur    **curp = &info->sc->sa.rmap_cur;
        xfs_fileoff_t           offset;
        unsigned int            rflags = 0;
        int                     has_rmap;
        int                     error;
 
+       if (xfs_ifork_is_realtime(info->sc->ip, info->whichfork))
+               curp = &info->sc->sr.rmap_cur;
+
+       if (*curp == NULL)
+               return false;
+
        if (info->whichfork == XFS_ATTR_FORK)
                rflags |= XFS_RMAP_ATTR_FORK;
        if (irec->br_state == XFS_EXT_UNWRITTEN)
@@ -172,13 +179,13 @@ xchk_bmap_get_rmap(
         * range rmap lookup to make sure we get the correct owner/offset.
         */
        if (info->is_shared) {
-               error = xfs_rmap_lookup_le_range(info->sc->sa.rmap_cur, agbno,
-                               owner, offset, rflags, rmap, &has_rmap);
+               error = xfs_rmap_lookup_le_range(*curp, bno, owner, offset,
+                               rflags, rmap, &has_rmap);
        } else {
-               error = xfs_rmap_lookup_le(info->sc->sa.rmap_cur, agbno,
-                               owner, offset, rflags, rmap, &has_rmap);
+               error = xfs_rmap_lookup_le(*curp, bno, owner, offset,
+                               rflags, rmap, &has_rmap);
        }
-       if (!xchk_should_check_xref(info->sc, &error, &info->sc->sa.rmap_cur))
+       if (!xchk_should_check_xref(info->sc, &error, curp))
                return false;
 
        if (!has_rmap)
@@ -192,29 +199,29 @@ STATIC void
 xchk_bmap_xref_rmap(
        struct xchk_bmap_info   *info,
        struct xfs_bmbt_irec    *irec,
-       xfs_agblock_t           agbno)
+       xfs_agblock_t           bno)
 {
        struct xfs_rmap_irec    rmap;
        unsigned long long      rmap_end;
        uint64_t                owner = info->sc->ip->i_ino;
 
-       if (!info->sc->sa.rmap_cur || xchk_skip_xref(info->sc->sm))
+       if (xchk_skip_xref(info->sc->sm))
                return;
 
        /* Find the rmap record for this irec. */
-       if (!xchk_bmap_get_rmap(info, irec, agbno, owner, &rmap))
+       if (!xchk_bmap_get_rmap(info, irec, bno, owner, &rmap))
                return;
 
        /*
         * The rmap must be an exact match for this incore file mapping record,
         * which may have arisen from multiple ondisk records.
         */
-       if (rmap.rm_startblock != agbno)
+       if (rmap.rm_startblock != bno)
                xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
                                irec->br_startoff);
 
        rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount;
-       if (rmap_end != agbno + irec->br_blockcount)
+       if (rmap_end != bno + irec->br_blockcount)
                xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
                                irec->br_startoff);
 
@@ -259,7 +266,7 @@ STATIC void
 xchk_bmap_xref_rmap_cow(
        struct xchk_bmap_info   *info,
        struct xfs_bmbt_irec    *irec,
-       xfs_agblock_t           agbno)
+       xfs_agblock_t           bno)
 {
        struct xfs_rmap_irec    rmap;
        unsigned long long      rmap_end;
@@ -269,7 +276,7 @@ xchk_bmap_xref_rmap_cow(
                return;
 
        /* Find the rmap record for this irec. */
-       if (!xchk_bmap_get_rmap(info, irec, agbno, owner, &rmap))
+       if (!xchk_bmap_get_rmap(info, irec, bno, owner, &rmap))
                return;
 
        /*
@@ -277,12 +284,12 @@ xchk_bmap_xref_rmap_cow(
         * can start before and end after the physical space allocated to this
         * mapping.  There are no offsets to check.
         */
-       if (rmap.rm_startblock > agbno)
+       if (rmap.rm_startblock > bno)
                xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
                                irec->br_startoff);
 
        rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount;
-       if (rmap_end < agbno + irec->br_blockcount)
+       if (rmap_end < bno + irec->br_blockcount)
                xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
                                irec->br_startoff);
 
@@ -315,6 +322,8 @@ xchk_bmap_rt_iextent_xref(
        struct xchk_bmap_info   *info,
        struct xfs_bmbt_irec    *irec)
 {
+       struct xfs_owner_info   oinfo;
+       xfs_rgblock_t           rgbno;
        int                     error;
 
        error = xchk_rtgroup_init_existing(info->sc,
@@ -332,6 +341,19 @@ xchk_bmap_rt_iextent_xref(
        xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
                        irec->br_blockcount);
 
+       if (!xfs_has_rtrmapbt(info->sc->mp))
+               goto out_cur;
+
+       rgbno = xfs_rtb_to_rgbno(info->sc->mp, irec->br_startblock);
+       xchk_bmap_xref_rmap(info, irec, rgbno);
+
+       xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino, info->whichfork,
+                       irec->br_startoff);
+       xchk_xref_is_only_rt_owned_by(info->sc, rgbno,
+                       irec->br_blockcount, &oinfo);
+
+out_cur:
+       xchk_rtgroup_btcur_free(&info->sc->sr);
 out_free:
        xchk_rtgroup_free(info->sc, &info->sc->sr);
 }
index e062c7d12565cd47638050bcb2f6736183c8d568..d189732d0e24fb2361a0b91ecce3e852967b812e 100644 (file)
@@ -13,6 +13,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_rmap.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/repair.h"
@@ -34,6 +35,7 @@ xchk_rgsuperblock_xref(
                return;
 
        xchk_xref_is_used_rt_space(sc, xfs_rgbno_to_rtb(sc->sr.rtg, 0), 1);
+       xchk_xref_is_only_rt_owned_by(sc, 0, 1, &XFS_RMAP_OINFO_FS);
 }
 
 int
index 023d974f7994b1eb26ce374a8083eaee143bfb20..1b925eed7dd4cca20d68e9cac9b6d2e8da1f19b9 100644 (file)
@@ -9,17 +9,22 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
+#include "xfs_btree.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
 #include "xfs_rtbitmap.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_bit.h"
+#include "xfs_rtgroup.h"
 #include "xfs_sb.h"
+#include "xfs_rmap.h"
+#include "xfs_rtrmap_btree.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/repair.h"
 #include "scrub/rtbitmap.h"
+#include "scrub/btree.h"
 
 /* Set us up with the realtime metadata locked. */
 int
@@ -37,6 +42,7 @@ xchk_setup_rtbitmap(
        if (!rtb)
                return -ENOMEM;
        sc->buf = rtb;
+       rtb->sc = sc;
 
        error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr);
        if (error)
@@ -79,7 +85,30 @@ xchk_setup_rtbitmap(
        return 0;
 }
 
-/* Realtime bitmap. */
+/* Per-rtgroup bitmap contents. */
+
+/* Cross-reference rtbitmap entries with other metadata. */
+STATIC void
+xchk_rtbitmap_xref(
+       struct xchk_rtbitmap    *rtb,
+       xfs_rtblock_t           startblock,
+       xfs_rtblock_t           blockcount)
+{
+       struct xfs_scrub        *sc = rtb->sc;
+       xfs_rgblock_t           rgbno = xfs_rtb_to_rgbno(sc->mp, startblock);
+
+       if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
+               return;
+       if (!sc->sr.rmap_cur)
+               return;
+
+       xchk_xref_has_no_rt_owner(sc, rgbno, blockcount);
+
+       if (rtb->next_free_rgbno < rgbno)
+               xchk_xref_has_rt_owner(sc, rtb->next_free_rgbno,
+                               rgbno - rtb->next_free_rgbno);
+       rtb->next_free_rgbno = rgbno + blockcount;
+}
 
 /* Scrub a free extent record from the realtime bitmap. */
 STATIC int
@@ -89,7 +118,8 @@ xchk_rtbitmap_rec(
        const struct xfs_rtalloc_rec *rec,
        void                    *priv)
 {
-       struct xfs_scrub        *sc = priv;
+       struct xchk_rtbitmap    *rtb = priv;
+       struct xfs_scrub        *sc = rtb->sc;
        xfs_rtblock_t           startblock;
        xfs_filblks_t           blockcount;
 
@@ -98,6 +128,12 @@ xchk_rtbitmap_rec(
 
        if (!xfs_verify_rtbext(rtg_mount(rtg), startblock, blockcount))
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
+
+       xchk_rtbitmap_xref(rtb, startblock, blockcount);
+
+       if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
+               return -ECANCELED;
+
        return 0;
 }
 
@@ -145,7 +181,7 @@ xchk_rtbitmap_check_extents(
        return error;
 }
 
-/* Scrub the realtime bitmap. */
+/* Scrub this group's realtime bitmap. */
 int
 xchk_rtbitmap(
        struct xfs_scrub        *sc)
@@ -154,6 +190,7 @@ xchk_rtbitmap(
        struct xfs_rtgroup      *rtg = sc->sr.rtg;
        struct xfs_inode        *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP];
        struct xchk_rtbitmap    *rtb = sc->buf;
+       xfs_rgblock_t           last_rgbno;
        int                     error;
 
        /* Is sb_rextents correct? */
@@ -206,10 +243,20 @@ xchk_rtbitmap(
        if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
                return error;
 
-       error = xfs_rtalloc_query_all(rtg, sc->tp, xchk_rtbitmap_rec, sc);
+       rtb->next_free_rgbno = 0;
+       error = xfs_rtalloc_query_all(rtg, sc->tp, xchk_rtbitmap_rec, rtb);
        if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
                return error;
 
+       /*
+        * Check that the are rmappings for all rt extents between the end of
+        * the last free extent we saw and the last possible extent in the rt
+        * group.
+        */
+       last_rgbno = rtg->rtg_extents * mp->m_sb.sb_rextsize - 1;
+       if (rtb->next_free_rgbno < last_rgbno)
+               xchk_xref_has_rt_owner(sc, rtb->next_free_rgbno,
+                               last_rgbno - rtb->next_free_rgbno);
        return 0;
 }
 
index 85304ff019e1dceabadf86cdef47a5bec489ca62..dd5b394d9697d2a432451498a03d6fda77fcb666 100644 (file)
@@ -7,10 +7,15 @@
 #define __XFS_SCRUB_RTBITMAP_H__
 
 struct xchk_rtbitmap {
+       struct xfs_scrub        *sc;
+
        uint64_t                rextents;
        uint64_t                rbmblocks;
        unsigned int            rextslog;
        unsigned int            resblks;
+
+       /* The next free rt group block number that we expect to see. */
+       xfs_rgblock_t           next_free_rgbno;
 };
 
 #ifdef CONFIG_XFS_ONLINE_REPAIR
index 49d0ed9f6298f816f00f9b69a8c532f7ed5e2149..cd2416117f7f3603aec2458828054a44e3652812 100644 (file)
@@ -198,3 +198,68 @@ xchk_rtrmapbt(
        xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, XFS_DATA_FORK);
        return xchk_btree(sc, sc->sr.rmap_cur, xchk_rtrmapbt_rec, &oinfo, &cr);
 }
+
+/* xref check that the extent has no realtime reverse mapping at all */
+void
+xchk_xref_has_no_rt_owner(
+       struct xfs_scrub        *sc,
+       xfs_rgblock_t           bno,
+       xfs_extlen_t            len)
+{
+       enum xbtree_recpacking  outcome;
+       int                     error;
+
+       if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
+               return;
+
+       error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome);
+       if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
+               return;
+       if (outcome != XBTREE_RECPACKING_EMPTY)
+               xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
+}
+
+/* xref check that the extent is completely mapped */
+void
+xchk_xref_has_rt_owner(
+       struct xfs_scrub        *sc,
+       xfs_rgblock_t           bno,
+       xfs_extlen_t            len)
+{
+       enum xbtree_recpacking  outcome;
+       int                     error;
+
+       if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
+               return;
+
+       error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome);
+       if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
+               return;
+       if (outcome != XBTREE_RECPACKING_FULL)
+               xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
+}
+
+/* xref check that the extent is only owned by a given owner */
+void
+xchk_xref_is_only_rt_owned_by(
+       struct xfs_scrub                *sc,
+       xfs_agblock_t                   bno,
+       xfs_extlen_t                    len,
+       const struct xfs_owner_info     *oinfo)
+{
+       struct xfs_rmap_matches         res;
+       int                             error;
+
+       if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
+               return;
+
+       error = xfs_rmap_count_owners(sc->sr.rmap_cur, bno, len, oinfo, &res);
+       if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
+               return;
+       if (res.matches != 1)
+               xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
+       if (res.bad_non_owner_matches)
+               xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
+       if (res.non_owner_matches)
+               xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
+}
index 7cc3fa31a7d922f10d4da808110d465e9912cdb7..582faa927be719a725daa29f600d67232077cd0c 100644 (file)
@@ -316,8 +316,17 @@ void xchk_xref_is_not_cow_staging(struct xfs_scrub *sc, xfs_agblock_t bno,
 #ifdef CONFIG_XFS_RT
 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_rgblock_t rgbno,
+               xfs_extlen_t len);
+void xchk_xref_has_rt_owner(struct xfs_scrub *sc, xfs_rgblock_t rgbno,
+               xfs_extlen_t len);
+void xchk_xref_is_only_rt_owned_by(struct xfs_scrub *sc, xfs_rgblock_t rgbno,
+               xfs_extlen_t len, const struct xfs_owner_info *oinfo);
 #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_has_rt_owner(sc, rtbno, len) do { } while (0)
+# define xchk_xref_is_only_rt_owned_by(sc, bno, len, oinfo) do { } while (0)
 #endif
 
 #endif /* __XFS_SCRUB_SCRUB_H__ */