]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_db: introduce the 'fsmap' command to find what owns a set of fsblocks
authorDarrick J. Wong <darrick.wong@oracle.com>
Thu, 18 Aug 2016 23:47:57 +0000 (09:47 +1000)
committerDave Chinner <david@fromorbit.com>
Thu, 18 Aug 2016 23:47:57 +0000 (09:47 +1000)
Introduce a new 'fsmap' command to the fs debugger that will query the
rmap btree to report the file/metadata extents mapped to a range of
physical blocks.

[dchinner: xfs_rmap_query_range -> libxfs_rmap_query_range]

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
db/Makefile
db/command.c
db/fsmap.c [new file with mode: 0644]
db/fsmap.h [new file with mode: 0644]
libxfs/libxfs_api_defs.h
man/man8/xfs_db.8

index 8260da3fc2063ccefbbf81b95b5443a94e3fe91a..5adea489b4d6aa96ea2272068cc84b094b50c9f0 100644 (file)
@@ -12,7 +12,7 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
        dir2.h dir2sf.h dquot.h echo.h faddr.h field.h \
        flist.h fprint.h frag.h freesp.h hash.h help.h init.h inode.h input.h \
        io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \
-        sig.h strvec.h text.h type.h write.h attrset.h symlink.h
+        sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h
 CFILES = $(HFILES:.h=.c)
 LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh
 
index 3c17a1e4d6955bbe1bb636c11a6b466e68a536bd..278c3578b82d42b457b8ba6c282f364927ce0e92 100644 (file)
@@ -49,6 +49,7 @@
 #include "write.h"
 #include "malloc.h"
 #include "dquot.h"
+#include "fsmap.h"
 
 cmdinfo_t      *cmdtab;
 int            ncmds;
@@ -128,6 +129,7 @@ init_commands(void)
        echo_init();
        frag_init();
        freesp_init();
+       fsmap_init();
        help_init();
        hash_init();
        inode_init();
diff --git a/db/fsmap.c b/db/fsmap.c
new file mode 100644 (file)
index 0000000..b2ba55d
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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);
+}
diff --git a/db/fsmap.h b/db/fsmap.h
new file mode 100644 (file)
index 0000000..f8aacd3
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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);
index 8d2a53c0cc1bebd5872d93cc33e0ace810fae2cd..337363d7f27de6689539c4cbd2b81c16b14e8917 100644 (file)
@@ -99,6 +99,8 @@
 #define xfs_idata_realloc              libxfs_idata_realloc
 #define xfs_idestroy_fork              libxfs_idestroy_fork
 
+#define xfs_rmap_query_range           libxfs_rmap_query_range
+
 #define xfs_log_sb                     libxfs_log_sb
 #define xfs_sb_from_disk               libxfs_sb_from_disk
 #define xfs_sb_quota_from_disk         libxfs_sb_quota_from_disk
index a380f7873585bcfd64020a038f36b6ecf1942355..e17791360b2921fa3289dd86a474f0be55caab71 100644 (file)
@@ -568,6 +568,15 @@ command to convert to and from this form. Block numbers given for file blocks
 .B bmap
 command) are in this form.
 .TP
+.BI "fsmap [ " start " ] [ " end " ]
+Prints the mapping of disk blocks used by an XFS filesystem.  The map
+lists each extent used by files, allocation group metadata,
+journalling logs, and static filesystem metadata, as well as any
+regions that are unused.  All blocks, offsets, and lengths are specified
+in units of 512-byte blocks, no matter what the filesystem's block size is.
+.BI "The optional " start " and " end " arguments can be used to constrain
+the output to a particular range of disk blocks.
+.TP
 .BI hash " string
 Prints the hash value of
 .I string