]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_db: copy the realtime rmap btree
authorDarrick J. Wong <djwong@kernel.org>
Mon, 24 Feb 2025 18:21:58 +0000 (10:21 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 25 Feb 2025 17:16:00 +0000 (09:16 -0800)
Copy the realtime rmapbt when we're metadumping the filesystem.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
db/metadump.c

index 4d090942bf29cd06eccfdddeb57de08cba67a942..7d6e137f0c590624d223d6f2fc0bde494c19833f 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,14 @@ process_inode_data(
 
        case XFS_DINODE_FMT_BTREE:
                return process_btinode(dip, XFS_DATA_FORK);
+
+       case XFS_DINODE_FMT_META_BTREE:
+               switch (be16_to_cpu(dip->di_metatype)) {
+               case XFS_METAFILE_RTRMAP:
+                       return process_rtrmap(dip);
+               default:
+                       return 1;
+               }
        }
        return 1;
 }