xfs: cross-reference rmap records with free space btrees
authorDarrick J. Wong <djwong@kernel.org>
Wed, 12 Apr 2023 02:00:38 +0000 (19:00 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 12 Apr 2023 02:00:38 +0000 (19:00 -0700)
Strengthen the rmap btree record checker a little more by comparing
OWN_AG reverse mappings against the free space btrees, the rmap btree,
and the AGFL.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/scrub/bitmap.c
fs/xfs/scrub/bitmap.h
fs/xfs/scrub/rmap.c

index 85e5bed..0c959be 100644 (file)
@@ -6,6 +6,7 @@
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_shared.h"
+#include "xfs_bit.h"
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
@@ -262,6 +263,38 @@ xbitmap_disunion(
  * For the 300th record we just exit, with the list being [1, 4, 2, 3].
  */
 
+/* Mark a btree block to the agblock bitmap. */
+STATIC int
+xagb_bitmap_visit_btblock(
+       struct xfs_btree_cur    *cur,
+       int                     level,
+       void                    *priv)
+{
+       struct xagb_bitmap      *bitmap = priv;
+       struct xfs_buf          *bp;
+       xfs_fsblock_t           fsbno;
+       xfs_agblock_t           agbno;
+
+       xfs_btree_get_block(cur, level, &bp);
+       if (!bp)
+               return 0;
+
+       fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp));
+       agbno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno);
+
+       return xagb_bitmap_set(bitmap, agbno, 1);
+}
+
+/* Mark all (per-AG) btree blocks in the agblock bitmap. */
+int
+xagb_bitmap_set_btblocks(
+       struct xagb_bitmap      *bitmap,
+       struct xfs_btree_cur    *cur)
+{
+       return xfs_btree_visit_blocks(cur, xagb_bitmap_visit_btblock,
+                       XFS_BTREE_VISIT_ALL, bitmap);
+}
+
 /*
  * Record all the buffers pointed to by the btree cursor.  Callers already
  * engaged in a btree walk should call this function to capture the list of
index 55441fe..8498172 100644 (file)
@@ -108,4 +108,7 @@ static inline int xagb_bitmap_walk(struct xagb_bitmap *bitmap,
        return xbitmap_walk(&bitmap->agbitmap, fn, priv);
 }
 
+int xagb_bitmap_set_btblocks(struct xagb_bitmap *bitmap,
+               struct xfs_btree_cur *cur);
+
 #endif /* __XFS_SCRUB_BITMAP_H__ */
index 759349c..1febadb 100644 (file)
@@ -7,13 +7,17 @@
 #include "xfs_fs.h"
 #include "xfs_shared.h"
 #include "xfs_format.h"
+#include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
+#include "xfs_trans.h"
 #include "xfs_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_refcount.h"
 #include "xfs_ag.h"
 #include "xfs_bit.h"
+#include "xfs_alloc.h"
+#include "xfs_alloc_btree.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
@@ -51,6 +55,7 @@ struct xchk_rmap {
        /* Bitmaps containing all blocks for each type of AG metadata. */
        struct xagb_bitmap      fs_owned;
        struct xagb_bitmap      log_owned;
+       struct xagb_bitmap      ag_owned;
 
        /* Did we complete the AG space metadata bitmaps? */
        bool                    bitmaps_complete;
@@ -291,6 +296,9 @@ xchk_rmapbt_mark_bitmap(
        case XFS_RMAP_OWN_LOG:
                bmp = &cr->log_owned;
                break;
+       case XFS_RMAP_OWN_AG:
+               bmp = &cr->ag_owned;
+               break;
        }
 
        if (!bmp)
@@ -343,9 +351,26 @@ xchk_rmapbt_rec(
        return xchk_rmapbt_mark_bitmap(bs, cr, &irec);
 }
 
+/* Add an AGFL block to the rmap list. */
+STATIC int
+xchk_rmapbt_walk_agfl(
+       struct xfs_mount        *mp,
+       xfs_agblock_t           agbno,
+       void                    *priv)
+{
+       struct xagb_bitmap      *bitmap = priv;
+
+       return xagb_bitmap_set(bitmap, agbno, 1);
+}
+
 /*
  * Set up bitmaps mapping all the AG metadata to compare with the rmapbt
  * records.
+ *
+ * Grab our own btree cursors here if the scrub setup function didn't give us a
+ * btree cursor due to reports of poor health.  We need to find out if the
+ * rmapbt disagrees with primary metadata btrees to tag the rmapbt as being
+ * XCORRUPT.
  */
 STATIC int
 xchk_rmapbt_walk_ag_metadata(
@@ -353,6 +378,9 @@ xchk_rmapbt_walk_ag_metadata(
        struct xchk_rmap        *cr)
 {
        struct xfs_mount        *mp = sc->mp;
+       struct xfs_buf          *agfl_bp;
+       struct xfs_agf          *agf = sc->sa.agf_bp->b_addr;
+       struct xfs_btree_cur    *cur;
        int                     error;
 
        /* OWN_FS: AG headers */
@@ -370,6 +398,39 @@ xchk_rmapbt_walk_ag_metadata(
                        goto out;
        }
 
+       /* OWN_AG: bnobt, cntbt, rmapbt, and AGFL */
+       cur = sc->sa.bno_cur;
+       if (!cur)
+               cur = xfs_allocbt_init_cursor(sc->mp, sc->tp, sc->sa.agf_bp,
+                               sc->sa.pag, XFS_BTNUM_BNO);
+       error = xagb_bitmap_set_btblocks(&cr->ag_owned, cur);
+       if (cur != sc->sa.bno_cur)
+               xfs_btree_del_cursor(cur, error);
+       if (error)
+               goto out;
+
+       cur = sc->sa.cnt_cur;
+       if (!cur)
+               cur = xfs_allocbt_init_cursor(sc->mp, sc->tp, sc->sa.agf_bp,
+                               sc->sa.pag, XFS_BTNUM_CNT);
+       error = xagb_bitmap_set_btblocks(&cr->ag_owned, cur);
+       if (cur != sc->sa.cnt_cur)
+               xfs_btree_del_cursor(cur, error);
+       if (error)
+               goto out;
+
+       error = xagb_bitmap_set_btblocks(&cr->ag_owned, sc->sa.rmap_cur);
+       if (error)
+               goto out;
+
+       error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &agfl_bp);
+       if (error)
+               goto out;
+
+       error = xfs_agfl_walk(sc->mp, agf, agfl_bp, xchk_rmapbt_walk_agfl,
+                       &cr->ag_owned);
+       xfs_trans_brelse(sc->tp, agfl_bp);
+
 out:
        /*
         * If there's an error, set XFAIL and disable the bitmap
@@ -411,6 +472,9 @@ xchk_rmapbt_check_bitmaps(
 
        if (xagb_bitmap_hweight(&cr->log_owned) != 0)
                xchk_btree_xref_set_corrupt(sc, cur, level);
+
+       if (xagb_bitmap_hweight(&cr->ag_owned) != 0)
+               xchk_btree_xref_set_corrupt(sc, cur, level);
 }
 
 /* Scrub the rmap btree for some AG. */
@@ -427,6 +491,7 @@ xchk_rmapbt(
 
        xagb_bitmap_init(&cr->fs_owned);
        xagb_bitmap_init(&cr->log_owned);
+       xagb_bitmap_init(&cr->ag_owned);
 
        error = xchk_rmapbt_walk_ag_metadata(sc, cr);
        if (error)
@@ -440,6 +505,7 @@ xchk_rmapbt(
        xchk_rmapbt_check_bitmaps(sc, cr);
 
 out:
+       xagb_bitmap_destroy(&cr->ag_owned);
        xagb_bitmap_destroy(&cr->log_owned);
        xagb_bitmap_destroy(&cr->fs_owned);
        kfree(cr);