--- /dev/null
+/*
+ * Copyright (C) 2016 Oracle. All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libxfs.h"
+#include "command.h"
+#include "fsmap.h"
+#include "output.h"
+#include "init.h"
+
+struct fsmap_info {
+ unsigned long long nr;
+ xfs_agnumber_t agno;
+};
+
+static int
+fsmap_fn(
+ struct xfs_btree_cur *cur,
+ 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, info->agno, 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 void
+fsmap(
+ xfs_fsblock_t start_fsb,
+ xfs_fsblock_t end_fsb)
+{
+ struct fsmap_info info;
+ xfs_agnumber_t start_ag;
+ xfs_agnumber_t end_ag;
+ xfs_agnumber_t agno;
+ xfs_daddr_t eofs;
+ struct xfs_rmap_irec low;
+ struct xfs_rmap_irec high;
+ struct xfs_btree_cur *bt_cur;
+ struct xfs_buf *agbp;
+ int error;
+
+ eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
+ if (XFS_FSB_TO_DADDR(mp, end_fsb) >= eofs)
+ end_fsb = XFS_DADDR_TO_FSB(mp, eofs - 1);
+
+ low.rm_startblock = XFS_FSB_TO_AGBNO(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_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
+ end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
+
+ info.nr = 0;
+ for (agno = start_ag; agno <= end_ag; agno++) {
+ if (agno == end_ag)
+ high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsb);
+
+ error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
+ if (error) {
+ dbprintf(_("Error %d while reading AGF.\n"), error);
+ return;
+ }
+
+ bt_cur = xfs_rmapbt_init_cursor(mp, NULL, agbp, agno);
+ if (!bt_cur) {
+ libxfs_putbuf(agbp);
+ dbprintf(_("Not enough memory.\n"));
+ return;
+ }
+
+ info.agno = agno;
+ error = -libxfs_rmap_query_range(bt_cur, &low, &high,
+ fsmap_fn, &info);
+ if (error) {
+ xfs_btree_del_cursor(bt_cur, XFS_BTREE_ERROR);
+ libxfs_putbuf(agbp);
+ dbprintf(_("Error %d while querying fsmap btree.\n"),
+ error);
+ return;
+ }
+
+ xfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
+ libxfs_putbuf(agbp);
+
+ if (agno == start_ag)
+ low.rm_startblock = 0;
+ }
+}
+
+int
+fsmap_f(
+ int argc,
+ char **argv)
+{
+ char *p;
+ int c;
+ xfs_fsblock_t start_fsb = 0;
+ xfs_fsblock_t end_fsb = NULLFSBLOCK;
+
+ if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+ dbprintf(_("Filesystem does not support reverse mapping btree.\n"));
+ return 0;
+ }
+
+ while ((c = getopt(argc, argv, "")) != EOF) {
+ switch (c) {
+ default:
+ dbprintf(_("Bad option for fsmap command.\n"));
+ return 0;
+ }
+ }
+
+ if (argc > optind) {
+ start_fsb = strtoull(argv[optind], &p, 0);
+ if (*p != '\0' || start_fsb >= mp->m_sb.sb_dblocks) {
+ dbprintf(_("Bad fsmap start_fsb %s.\n"), argv[optind]);
+ return 0;
+ }
+ }
+
+ if (argc > optind + 1) {
+ end_fsb = strtoull(argv[optind + 1], &p, 0);
+ if (*p != '\0') {
+ dbprintf(_("Bad fsmap end_fsb %s.\n"), argv[optind + 1]);
+ return 0;
+ }
+ }
+
+ 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]"),
+ N_("display reverse mapping(s)"), NULL };
+
+void
+fsmap_init(void)
+{
+ add_command(&fsmap_cmd);
+}
--- /dev/null
+/*
+ * Copyright (C) 2016 Oracle. All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+extern void fsmap_init(void);