]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: scan rt rmap when we're doing an intense rmap check of bmbt mappings
authorDarrick J. Wong <djwong@kernel.org>
Fri, 9 Aug 2024 09:15:32 +0000 (11:15 +0200)
committerChristoph Hellwig <hch@lst.de>
Sun, 11 Aug 2024 06:28:33 +0000 (08:28 +0200)
Teach the bmbt scrubber how to perform a comprehensive check that the
rmapbt does not contain /any/ mappings that are not described by bmbt
records when it's dealing with a realtime file.

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

index 71152866a6819d2d0bf1fb20c7957058130d6a75..2f3a0d50a471190fcbedb7ff268f48f4c37f2a11 100644 (file)
@@ -21,6 +21,8 @@
 #include "xfs_rmap_btree.h"
 #include "xfs_rtgroup.h"
 #include "xfs_health.h"
+#include "xfs_rtalloc.h"
+#include "xfs_rtrmap_btree.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
@@ -635,12 +637,20 @@ xchk_bmap_check_rmap(
         */
        check_rec = *rec;
        while (have_map) {
+               xfs_fsblock_t   startblock;
+
                if (irec.br_startoff != check_rec.rm_offset)
                        xchk_fblock_set_corrupt(sc, sbcri->whichfork,
                                        check_rec.rm_offset);
-               if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp,
-                               cur->bc_ag.pag->pag_agno,
-                               check_rec.rm_startblock))
+               if (xfs_btree_is_rmap(cur->bc_ops))
+                       startblock = XFS_AGB_TO_FSB(sc->mp,
+                                       cur->bc_ag.pag->pag_agno,
+                                       check_rec.rm_startblock);
+               else
+                       startblock = xfs_rgbno_to_rtb(sc->mp,
+                                       cur->bc_ino.rtg->rtg_rgno,
+                                       check_rec.rm_startblock);
+               if (irec.br_startblock != startblock)
                        xchk_fblock_set_corrupt(sc, sbcri->whichfork,
                                        check_rec.rm_offset);
                if (irec.br_blockcount > check_rec.rm_blockcount)
@@ -694,6 +704,31 @@ xchk_bmap_check_ag_rmaps(
        return error;
 }
 
+/* Make sure each rt rmap has a corresponding bmbt entry. */
+STATIC int
+xchk_bmap_check_rt_rmaps(
+       struct xfs_scrub                *sc,
+       struct xfs_rtgroup              *rtg)
+{
+       struct xchk_bmap_check_rmap_info sbcri;
+       struct xfs_btree_cur            *cur;
+       int                             error;
+
+       xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP);
+       cur = xfs_rtrmapbt_init_cursor(sc->mp, sc->tp, rtg,
+                       rtg->rtg_inodes[XFS_RTG_RMAP]);
+
+       sbcri.sc = sc;
+       sbcri.whichfork = XFS_DATA_FORK;
+       error = xfs_rmap_query_all(cur, xchk_bmap_check_rmap, &sbcri);
+       if (error == -ECANCELED)
+               error = 0;
+
+       xfs_btree_del_cursor(cur, error);
+       xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP);
+       return error;
+}
+
 /*
  * Decide if we want to scan the reverse mappings to determine if the attr
  * fork /really/ has zero space mappings.
@@ -748,10 +783,6 @@ xchk_bmap_check_empty_datafork(
 {
        struct xfs_ifork        *ifp = &ip->i_df;
 
-       /* Don't support realtime rmap checks yet. */
-       if (XFS_IS_REALTIME_INODE(ip))
-               return false;
-
        /*
         * If the dinode repair found a bad data fork, it will reset the fork
         * to extents format with zero records and wait for the this scrubber
@@ -803,6 +834,22 @@ xchk_bmap_check_rmaps(
        xfs_agnumber_t          agno;
        int                     error;
 
+       if (xfs_ifork_is_realtime(sc->ip, whichfork)) {
+               struct xfs_rtgroup      *rtg;
+               xfs_rgnumber_t          rgno;
+
+               for_each_rtgroup(sc->mp, rgno, rtg) {
+                       error = xchk_bmap_check_rt_rmaps(sc, rtg);
+                       if (error ||
+                           (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
+                               xfs_rtgroup_rele(rtg);
+                               return error;
+                       }
+               }
+
+               return 0;
+       }
+
        for_each_perag(sc->mp, agno, pag) {
                error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag);
                if (error ||