[PATCH 10/27] xfs_db: make fsmap query the realtime reverse mapping tree

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

Extend the 'fsmap' debugger command to support querying the realtime
rmap btree via a new -r argument.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
db/fsmap.c | 149 +++++++++++++++++++++++++++++++++++++++++++++-
libxfs/libxfs_api_defs.h | 3 +
2 files changed, 148 insertions(+), 4 deletions(-)

diff --git a/db/fsmap.c b/db/fsmap.c
index a9259c4632185b..ddbe4e6a3dfcfa 100644
--- a/db/fsmap.c
+++ b/db/fsmap.c
@@ -102,6 +102,134 @@ fsmap(
}
}

+static int
+fsmap_rt_fn(
+ struct xfs_btree_cur *cur,
+ const struct xfs_rmap_irec *rec,
+ void *priv)
+{
+ struct fsmap_info *info = priv;
+
+ dbprintf(_("%llu: %u/%u len %u owner %lld offset %llu bmbt %d attrfork %d extflag %d\n"),
+ info->nr, cur->bc_group->xg_gno, rec->rm_startblock,
+ rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
+ !!(rec->rm_flags & XFS_RMAP_BMBT_BLOCK),
+ !!(rec->rm_flags & XFS_RMAP_ATTR_FORK),
+ !!(rec->rm_flags & XFS_RMAP_UNWRITTEN));
+ info->nr++;
+
+ return 0;
+}
+
+static int
+fsmap_rtgroup(
+ struct xfs_rtgroup *rtg,
+ const struct xfs_rmap_irec *low,
+ const struct xfs_rmap_irec *high,
+ struct fsmap_info *info)
+{
+ struct xfs_mount *mp = rtg_mount(rtg);
+ struct xfs_trans *tp;
+ struct xfs_btree_cur *bt_cur;
+ int error;
+
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error) {
+ dbprintf(
+ _("Cannot alloc transaction to look up rtgroup %u rmap inode\n"),
+ rtg_rgno(rtg));
+ return error;
+ }
+
+ error = -libxfs_rtginode_load_parent(tp);
+ if (error) {
+ dbprintf(_("Cannot load realtime metadir, error %d\n"),
+ error);
+ goto out_trans;
+ }
+
+ error = -libxfs_rtginode_load(rtg, XFS_RTGI_RMAP, tp);
+ if (error) {
+ dbprintf(_("Cannot load rtgroup %u rmap inode, error %d\n"),
+ rtg_rgno(rtg), error);
+ goto out_rele_dp;
+ }
+
+ bt_cur = libxfs_rtrmapbt_init_cursor(tp, rtg);
+ if (!bt_cur) {
+ dbprintf(_("Not enough memory.\n"));
+ goto out_rele_ip;
+ }
+
+ error = -libxfs_rmap_query_range(bt_cur, low, high, fsmap_rt_fn,
+ info);
+ if (error) {
+ dbprintf(_("Error %d while querying rt fsmap btree.\n"),
+ error);
+ goto out_cur;
+ }
+
+out_cur:
+ libxfs_btree_del_cursor(bt_cur, error);
+out_rele_ip:
+ libxfs_rtginode_irele(&rtg->rtg_inodes[XFS_RTGI_RMAP]);
+out_rele_dp:
+ libxfs_rtginode_irele(&mp->m_rtdirip);
+out_trans:
+ libxfs_trans_cancel(tp);
+ return error;
+}
+
+static void
+fsmap_rt(
+ xfs_fsblock_t start_fsb,
+ xfs_fsblock_t end_fsb)
+{
+ struct fsmap_info info;
+ xfs_daddr_t eofs;
+ struct xfs_rmap_irec low;
+ struct xfs_rmap_irec high;
+ struct xfs_rtgroup *rtg = NULL;
+ xfs_rgnumber_t start_rg;
+ xfs_rgnumber_t end_rg;
+ int error;
+
+ if (mp->m_sb.sb_rblocks == 0)
+ return;
+
+ eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
+ if (XFS_FSB_TO_DADDR(mp, end_fsb) >= eofs)
+ end_fsb = XFS_DADDR_TO_FSB(mp, eofs - 1);
+
+ low.rm_startblock = xfs_rtb_to_rgbno(mp, start_fsb);
+ low.rm_owner = 0;
+ low.rm_offset = 0;
+ low.rm_flags = 0;
+ high.rm_startblock = -1U;
+ high.rm_owner = ULLONG_MAX;
+ high.rm_offset = ULLONG_MAX;
+ high.rm_flags = XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK |
+ XFS_RMAP_UNWRITTEN;
+
+ start_rg = xfs_rtb_to_rgno(mp, start_fsb);
+ end_rg = xfs_rtb_to_rgno(mp, end_fsb);
+
+ info.nr = 0;
+ while ((rtg = xfs_rtgroup_next_range(mp, rtg, start_rg, end_rg))) {
+ if (rtg_rgno(rtg) == end_rg)
+ high.rm_startblock = xfs_rtb_to_rgbno(mp, end_fsb);
+
+ error = fsmap_rtgroup(rtg, &low, &high, &info);
+ if (error) {
+ libxfs_rtgroup_put(rtg);
+ return;
+ }
+
+ if (rtg_rgno(rtg) == start_rg)
+ low.rm_startblock = 0;
+ }
+}
+
static int
fsmap_f(
int argc,
@@ -111,14 +239,18 @@ fsmap_f(
int c;
xfs_fsblock_t start_fsb = 0;
xfs_fsblock_t end_fsb = NULLFSBLOCK;
+ bool isrt = false;

if (!xfs_has_rmapbt(mp)) {
dbprintf(_("Filesystem does not support reverse mapping btree.\n"));
return 0;
}

- while ((c = getopt(argc, argv, "")) != EOF) {
+ while ((c = getopt(argc, argv, "r")) != EOF) {
switch (c) {
+ case 'r':
+ isrt = true;
+ break;
default:
dbprintf(_("Bad option for fsmap command.\n"));
return 0;
@@ -141,14 +273,23 @@ fsmap_f(
}
}

- fsmap(start_fsb, end_fsb);
+ if (argc > optind + 2) {
+ exitcode = 1;
+ dbprintf(_("Too many arguments to fsmap.\n"));
+ return 0;
+ }
+
+ if (isrt)
+ fsmap_rt(start_fsb, end_fsb);
+ else
+ fsmap(start_fsb, end_fsb);

return 0;
}

static const cmdinfo_t fsmap_cmd =
- { "fsmap", NULL, fsmap_f, 0, 2, 0,
- N_("[start_fsb] [end_fsb]"),
+ { "fsmap", NULL, fsmap_f, 0, -1, 0,
+ N_("[-r] [start_fsb] [end_fsb]"),
N_("display reverse mapping(s)"), NULL };

void
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index cf88656946ab1b..3e521cd0c76063 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -295,6 +295,7 @@
#define xfs_rtginode_name libxfs_rtginode_name
#define xfs_rtsummary_create libxfs_rtsummary_create

+#define xfs_rtginode_irele libxfs_rtginode_irele
#define xfs_rtginode_load libxfs_rtginode_load
#define xfs_rtginode_load_parent libxfs_rtginode_load_parent
#define xfs_rtgroup_alloc libxfs_rtgroup_alloc
@@ -310,8 +311,10 @@
#define xfs_rtfree_extent libxfs_rtfree_extent
#define xfs_rtfree_blocks libxfs_rtfree_blocks
#define xfs_update_rtsb libxfs_update_rtsb
+#define xfs_rtgroup_put libxfs_rtgroup_put
#define xfs_rtrmapbt_droot_maxrecs libxfs_rtrmapbt_droot_maxrecs
#define xfs_rtrmapbt_maxlevels_ondisk libxfs_rtrmapbt_maxlevels_ondisk
+#define xfs_rtrmapbt_init_cursor libxfs_rtrmapbt_init_cursor
#define xfs_rtrmapbt_maxrecs libxfs_rtrmapbt_maxrecs

#define xfs_sb_from_disk libxfs_sb_from_disk