[PATCH 09/27] xfs_db: copy the realtime rmap btree

Darrick J. Wong
2025-02-06T22:52:05Z

Copy the realtime rmapbt when we're metadumping the filesystem.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
db/metadump.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 120 insertions(+)

diff --git a/db/metadump.c b/db/metadump.c
index 4f4b4f8a39a551..aa946746cdfa68 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -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;
}