]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_db: copy the realtime rmap btree
authorDarrick J. Wong <djwong@kernel.org>
Wed, 3 Jul 2024 21:22:21 +0000 (14:22 -0700)
committerChristoph Hellwig <hch@lst.de>
Sun, 11 Aug 2024 06:35:55 +0000 (08:35 +0200)
Copy the realtime rmapbt when we're metadumping the filesystem.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
db/metadump.c

index 1941f633ac1397dddc7ccc2d303f15d8a97f0436..758fd482012624b0748ff926f0e7de49feee8857 100644 (file)
@@ -589,6 +589,55 @@ copy_rmap_btree(
        return scan_btree(agno, root, levels, TYP_RMAPBT, agf, scanfunc_rmapbt);
 }
 
+static int
+scanfunc_rtrmapbt(
+       struct xfs_btree_block  *block,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           agbno,
+       int                     level,
+       typnm_t                 btype,
+       void                    *arg)
+{
+       xfs_rtrmap_ptr_t        *pp;
+       int                     i;
+       int                     numrecs;
+
+       if (level == 0)
+               return 1;
+
+       numrecs = be16_to_cpu(block->bb_numrecs);
+       if (numrecs > mp->m_rtrmap_mxr[1]) {
+               if (metadump.show_warnings)
+                       print_warning("invalid numrecs (%u) in %s block %u/%u",
+                               numrecs, typtab[btype].name, agno, agbno);
+               return 1;
+       }
+
+       pp = xfs_rtrmap_ptr_addr(block, 1, mp->m_rtrmap_mxr[1]);
+       for (i = 0; i < numrecs; i++) {
+               xfs_agnumber_t  pagno;
+               xfs_agblock_t   pbno;
+
+               pagno = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i]));
+               pbno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i]));
+
+               if (pbno == 0 || pbno > mp->m_sb.sb_agblocks ||
+                   pagno > mp->m_sb.sb_agcount) {
+                       if (metadump.show_warnings)
+                               print_warning("invalid block number (%u/%u) "
+                                               "in inode %llu %s block %u/%u",
+                                               pagno, pbno,
+                                               (unsigned long long)metadump.cur_ino,
+                                               typtab[btype].name, agno, agbno);
+                       continue;
+               }
+               if (!scan_btree(pagno, pbno, level, btype, arg,
+                               scanfunc_rtrmapbt))
+                       return 0;
+       }
+       return 1;
+}
+
 static int
 scanfunc_refcntbt(
        struct xfs_btree_block  *block,
@@ -2325,6 +2374,69 @@ process_exinode(
                        nex);
 }
 
+static int
+process_rtrmap(
+       struct xfs_dinode       *dip)
+{
+       int                     whichfork = XFS_DATA_FORK;
+       struct xfs_rtrmap_root  *dib =
+               (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, whichfork);
+       xfs_rtrmap_ptr_t        *pp;
+       int                     level = be16_to_cpu(dib->bb_level);
+       int                     nrecs = be16_to_cpu(dib->bb_numrecs);
+       typnm_t                 btype = TYP_RTRMAPBT;
+       int                     maxrecs;
+       int                     i;
+
+       if (level > mp->m_rtrmap_maxlevels) {
+               if (metadump.show_warnings)
+                       print_warning("invalid level (%u) in inode %lld %s "
+                                       "root", level,
+                                       (unsigned long long)metadump.cur_ino,
+                                       typtab[btype].name);
+               return 1;
+       }
+
+       if (level == 0)
+               return 1;
+
+       maxrecs = libxfs_rtrmapbt_droot_maxrecs(
+                       XFS_DFORK_SIZE(dip, mp, whichfork),
+                       false);
+       if (nrecs > maxrecs) {
+               if (metadump.show_warnings)
+                       print_warning("invalid numrecs (%u) in inode %lld %s "
+                                       "root", nrecs,
+                                       (unsigned long long)metadump.cur_ino,
+                                       typtab[btype].name);
+               return 1;
+       }
+
+       pp = xfs_rtrmap_droot_ptr_addr(dib, 1, maxrecs);
+       for (i = 0; i < nrecs; i++) {
+               xfs_agnumber_t  ag;
+               xfs_agblock_t   bno;
+
+               ag = XFS_FSB_TO_AGNO(mp, get_unaligned_be64(&pp[i]));
+               bno = XFS_FSB_TO_AGBNO(mp, get_unaligned_be64(&pp[i]));
+
+               if (bno == 0 || bno > mp->m_sb.sb_agblocks ||
+                               ag > mp->m_sb.sb_agcount) {
+                       if (metadump.show_warnings)
+                               print_warning("invalid block number (%u/%u) "
+                                               "in inode %llu %s root", ag,
+                                               bno,
+                                               (unsigned long long)metadump.cur_ino,
+                                               typtab[btype].name);
+                       continue;
+               }
+
+               if (!scan_btree(ag, bno, level, btype, NULL, scanfunc_rtrmapbt))
+                       return 0;
+       }
+       return 1;
+}
+
 static int
 process_inode_data(
        struct xfs_dinode       *dip)
@@ -2366,6 +2478,9 @@ process_inode_data(
 
        case XFS_DINODE_FMT_BTREE:
                return process_btinode(dip, XFS_DATA_FORK);
+
+       case XFS_DINODE_FMT_RMAP:
+               return process_rtrmap(dip);
        }
        return 1;
 }