@@ -597,6 +597,54 @@ 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 (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 (show_warnings)
+ print_warning("invalid block number (%u/%u) "
+ "in inode %llu %s block %u/%u",
+ pagno, pbno, (long long)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,
@@ -2336,6 +2384,80 @@ process_exinode(
whichfork), nex, itype, is_meta);
}
+static int
+process_rtrmap(
+ struct xfs_dinode *dip,
+ typnm_t itype)
+{
+ struct xfs_rtrmap_root *dib;
+ int i;
+ xfs_rtrmap_ptr_t *pp;
+ int level;
+ int nrecs;
+ int maxrecs;
+ int whichfork;
+ typnm_t btype;
+
+ if (itype == TYP_ATTR && show_warnings) {
+ print_warning("ignoring rtrmapbt root in inode %llu attr fork",
+ (long long)cur_ino);
+ return 1;
+ }
+
+ whichfork = XFS_DATA_FORK;
+ btype = TYP_RTRMAPBT;
+
+ dib = (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, whichfork);
+ level = be16_to_cpu(dib->bb_level);
+ nrecs = be16_to_cpu(dib->bb_numrecs);
+
+ if (level > mp->m_rtrmap_maxlevels) {
+ if (show_warnings)
+ print_warning("invalid level (%u) in inode %lld %s "
+ "root", level, (long long)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 (show_warnings)
+ print_warning("invalid numrecs (%u) in inode %lld %s "
+ "root", nrecs, (long long)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 (show_warnings)
+ print_warning("invalid block number (%u/%u) "
+ "in inode %llu %s root", ag,
+ bno, (long long)cur_ino,
+ typtab[btype].name);
+ continue;
+ }
+
+ if (!scan_btree(ag, bno, level, btype, &itype,
+ scanfunc_rtrmapbt))
+ return 0;
+ }
+ return 1;
+}
+
static int
process_inode_data(
struct xfs_dinode *dip,
@@ -2380,6 +2502,9 @@ process_inode_data(
case XFS_DINODE_FMT_BTREE:
return process_btinode(dip, itype);
+
+ case XFS_DINODE_FMT_RMAP:
+ return process_rtrmap(dip, itype);
}
return 1;
}