xfs_db: copy the realtime refcount btree
authorDarrick J. Wong <djwong@kernel.org>
Wed, 3 Jul 2024 21:22:33 +0000 (14:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 9 Jul 2024 22:37:24 +0000 (15:37 -0700)
Copy the realtime refcountbt when we're metadumping the filesystem.

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

index b34952524e74b3c54b4c41be45ca62c8dd3bbf9b..212bcad6f6b3bb00e20da43f8ffbe4c898f6b48f 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 {
@@ -2428,6 +2477,83 @@ process_rtrmap(
        return 1;
 }
 
+static int
+process_rtrefc(
+       struct xfs_dinode       *dip,
+       typnm_t                 itype)
+{
+       struct xfs_rtrefcount_root      *dib;
+       int                     i;
+       xfs_rtrefcount_ptr_t    *pp;
+       int                     level;
+       int                     nrecs;
+       int                     maxrecs;
+       int                     whichfork;
+       typnm_t                 btype;
+
+       if (itype == TYP_ATTR && metadump.show_warnings) {
+               print_warning("ignoring rtrefcbt root in inode %llu attr fork",
+                               (unsigned long long)metadump.cur_ino);
+               return 1;
+       }
+
+       whichfork = XFS_DATA_FORK;
+       btype = TYP_RTREFCBT;
+
+       dib = (struct xfs_rtrefcount_root *)XFS_DFORK_PTR(dip, whichfork);
+       level = be16_to_cpu(dib->bb_level);
+       nrecs = be16_to_cpu(dib->bb_numrecs);
+
+       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, &itype,
+                               scanfunc_rtrefcbt))
+                       return 0;
+       }
+       return 1;
+}
+
 static int
 process_inode_data(
        struct xfs_dinode       *dip,
@@ -2475,6 +2601,9 @@ process_inode_data(
 
                case XFS_DINODE_FMT_RMAP:
                        return process_rtrmap(dip, itype);
+
+               case XFS_DINODE_FMT_REFCOUNT:
+                       return process_rtrefc(dip, itype);
        }
        return 1;
 }