]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_db: copy the realtime refcount btree
authorDarrick J. Wong <djwong@kernel.org>
Mon, 24 Feb 2025 18:22:04 +0000 (10:22 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 25 Feb 2025 17:16:02 +0000 (09:16 -0800)
Copy the realtime refcountbt 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 7d6e137f0c590624d223d6f2fc0bde494c19833f..34f2d61700fe1d1746e7a4bdad313eb72a6f366c 100644 (file)
@@ -710,6 +710,55 @@ copy_refcount_btree(
        return scan_btree(agno, root, levels, TYP_REFCBT, agf, scanfunc_refcntbt);
 }
 
+static int
+scanfunc_rtrefcbt(
+       struct xfs_btree_block  *block,
+       xfs_agnumber_t          agno,
+       xfs_agblock_t           agbno,
+       int                     level,
+       typnm_t                 btype,
+       void                    *arg)
+{
+       xfs_rtrefcount_ptr_t    *pp;
+       int                     i;
+       int                     numrecs;
+
+       if (level == 0)
+               return 1;
+
+       numrecs = be16_to_cpu(block->bb_numrecs);
+       if (numrecs > mp->m_rtrefc_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_rtrefcount_ptr_addr(block, 1, mp->m_rtrefc_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_rtrefcbt))
+                       return 0;
+       }
+       return 1;
+}
+
 /* filename and extended attribute obfuscation routines */
 
 struct name_ent {
@@ -2437,6 +2486,69 @@ process_rtrmap(
        return 1;
 }
 
+static int
+process_rtrefc(
+       struct xfs_dinode       *dip)
+{
+       int                     whichfork = XFS_DATA_FORK;
+       struct xfs_rtrefcount_root *dib =
+               (struct xfs_rtrefcount_root *)XFS_DFORK_PTR(dip, whichfork);
+       int                     level = be16_to_cpu(dib->bb_level);
+       int                     nrecs = be16_to_cpu(dib->bb_numrecs);
+       typnm_t                 btype = TYP_RTREFCBT;
+       int                     maxrecs;
+       xfs_rtrefcount_ptr_t    *pp;
+       int                     i;
+
+       if (level > mp->m_rtrefc_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_rtrefcountbt_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_rtrefcount_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_rtrefcbt))
+                       return 0;
+       }
+       return 1;
+}
+
 static int
 process_inode_data(
        struct xfs_dinode       *dip)
@@ -2483,6 +2595,8 @@ process_inode_data(
                switch (be16_to_cpu(dip->di_metatype)) {
                case XFS_METAFILE_RTRMAP:
                        return process_rtrmap(dip);
+               case XFS_METAFILE_RTREFCOUNT:
+                       return process_rtrefc(dip);
                default:
                        return 1;
                }