]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: walk the rt reverse mapping tree when rebuilding rmap
authorDarrick J. Wong <djwong@kernel.org>
Tue, 15 Oct 2024 19:40:03 +0000 (12:40 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 5 Nov 2024 21:36:26 +0000 (13:36 -0800)
When we're rebuilding the data device rmap, if we encounter an "rmap"
format fork, we have to walk the (realtime) rmap btree inode to build
the appropriate mappings.

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

index a0a227d183d28d1118db4dd732b71467e4c139ad..e1a4ea48cc5a8cd83daa51b91ecc4b27ce9cdfe8 100644 (file)
@@ -31,6 +31,8 @@
 #include "xfs_refcount.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_ag.h"
+#include "xfs_rtrmap_btree.h"
+#include "xfs_rtgroup.h"
 #include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
@@ -499,6 +501,41 @@ xrep_rmap_scan_iext(
        return xrep_rmap_stash_accumulated(rf);
 }
 
+static int
+xrep_rmap_scan_rtrmapbt(
+       struct xrep_rmap_ifork  *rf,
+       struct xfs_inode        *ip)
+{
+       struct xfs_scrub        *sc = rf->rr->sc;
+       struct xfs_rtgroup      *rtg = NULL;
+       struct xfs_btree_cur    *cur;
+       int                     error;
+
+       if (rf->whichfork != XFS_DATA_FORK)
+               return -EFSCORRUPTED;
+
+       while ((rtg = xfs_rtgroup_next(sc->mp, rtg))) {
+               if (ip == rtg->rtg_inodes[XFS_RTGI_RMAP]) {
+                       cur = xfs_rtrmapbt_init_cursor(sc->tp, rtg);
+                       error = xrep_rmap_scan_iroot_btree(rf, cur);
+                       xfs_btree_del_cursor(cur, error);
+                       xfs_rtgroup_rele(rtg);
+                       return error;
+               }
+       }
+
+       /*
+        * We shouldn't find an rmap format inode that isn't associated with
+        * an rtgroup and has ondisk blocks allocated to it.
+        */
+       if (ip->i_nblocks) {
+               ASSERT(0);
+               return -EFSCORRUPTED;
+       }
+
+       return 0;
+}
+
 /* Find all the extents from a given AG in an inode fork. */
 STATIC int
 xrep_rmap_scan_ifork(
@@ -528,6 +565,8 @@ xrep_rmap_scan_ifork(
                error = xrep_rmap_scan_bmbt(&rf, ip, &mappings_done);
                if (error || mappings_done)
                        return error;
+       } else if (ifp->if_format == XFS_DINODE_FMT_RMAP) {
+               return xrep_rmap_scan_rtrmapbt(&rf, ip);
        } else if (ifp->if_format != XFS_DINODE_FMT_EXTENTS) {
                return 0;
        }