[PATCH 4/4] xfs_db: dump metadata btrees via 'btdump'

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Darrick J. Wong <darrick.wong@xxxxxxxxxx>

Introduce a new 'btdump' command that can print the contents of all
blocks of any metadata subtree in the filesystem.  This enables
developers and forensic analyst to view a metadata structure without
having to navigate the btree manually.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
 db/Makefile  |    2 
 db/btdump.c  |  272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 db/btdump.h  |   20 ++++
 db/command.c |    2 
 4 files changed, 295 insertions(+), 1 deletion(-)
 create mode 100644 db/btdump.c
 create mode 100644 db/btdump.h


diff --git a/db/Makefile b/db/Makefile
index cdc0b99..97dd898 100644
--- a/db/Makefile
+++ b/db/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs
 LTCOMMAND = xfs_db
 
 HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \
-	btblock.h bmroot.h check.h command.h convert.h crc.h debug.h \
+	btblock.h btdump.h bmroot.h check.h command.h convert.h crc.h debug.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 \
diff --git a/db/btdump.c b/db/btdump.c
new file mode 100644
index 0000000..7824c33
--- /dev/null
+++ b/db/btdump.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2017 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
+ *
+ * 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 "output.h"
+#include "init.h"
+#include "io.h"
+#include "type.h"
+#include "btdump.h"
+#include "input.h"
+
+static void
+btdump_help(void)
+{
+	dbprintf(_(
+"\n"
+" 'btdump' dumps the btree rooted at the current io cursor location.\n"
+" In the case of an inode, the data fork bmbt is displayed.\n"
+" Options:\n"
+"   -a -- Display the extended attribute bmbt.\n"
+"   -i -- Print internal btree nodes.\n"
+"\n"
+));
+
+}
+
+static int
+eval(
+	const char	*fmt, ...)
+{
+	va_list		ap;
+	char		buf[PATH_MAX];
+	char		**v;
+	int		c;
+	int		ret;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+
+	v = breakline(buf, &c);
+	ret = command(c, v);
+	free(v);
+	return ret;
+}
+
+static bool
+btblock_has_rightsib(
+	struct xfs_btree_block	*block,
+	bool			long_format)
+{
+	if (long_format)
+		return block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK);
+	return block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK);
+}
+
+static int
+dump_btlevel(
+	int			level,
+	bool			long_format)
+{
+	xfs_daddr_t		orig_daddr = iocur_top->bb;
+	xfs_daddr_t		last_daddr;
+	unsigned int		nr;
+	int			ret;
+
+	ret = eval("push");
+	if (ret)
+		return ret;
+
+	nr = 1;
+	do {
+		last_daddr = iocur_top->bb;
+		dbprintf(_("%s level %u block %u daddr %llu\n"),
+			 iocur_top->typ->name, level, nr, last_daddr);
+		if (level > 0) {
+			ret = eval("print keys");
+			if (ret)
+				goto err;
+			ret = eval("print ptrs");
+		} else {
+			ret = eval("print recs");
+		}
+		if (ret)
+			goto err;
+		if (btblock_has_rightsib(iocur_top->data, long_format)) {
+			ret = eval("addr rightsib");
+			if (ret)
+				goto err;
+		}
+		nr++;
+	} while (iocur_top->bb != orig_daddr && iocur_top->bb != last_daddr);
+
+	ret = eval("pop");
+	return ret;
+err:
+	eval("pop");
+	return ret;
+}
+
+static int
+dump_btree(
+	bool		dump_node_blocks,
+	bool		long_format)
+{
+	xfs_daddr_t	orig_daddr = iocur_top->bb;
+	xfs_daddr_t	last_daddr;
+	int		level;
+	int		ret;
+
+	ret = eval("push");
+	if (ret)
+		return ret;
+
+	cur_agno = XFS_FSB_TO_AGNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb));
+	level = xfs_btree_get_level(iocur_top->data);
+	do {
+		last_daddr = iocur_top->bb;
+		if (level > 0) {
+			if (dump_node_blocks) {
+				ret = dump_btlevel(level, long_format);
+				if (ret)
+					goto err;
+			}
+			ret = eval("addr ptrs[1]");
+		} else {
+			ret = dump_btlevel(level, long_format);
+		}
+		if (ret)
+			goto err;
+		level--;
+	} while (level >= 0 &&
+		 iocur_top->bb != orig_daddr &&
+		 iocur_top->bb != last_daddr);
+
+	ret = eval("pop");
+	return ret;
+err:
+	eval("pop");
+	return ret;
+}
+
+static int
+dump_inode(
+	bool			dump_node_blocks,
+	bool			attrfork)
+{
+	char			*prefix;
+	struct xfs_dinode	*dip;
+	int			ret;
+
+	if (attrfork)
+		prefix = "a.bmbt";
+	else if (xfs_sb_version_hascrc(&mp->m_sb))
+		prefix = "u3.bmbt";
+	else
+		prefix = "u.bmbt";
+
+	dip = iocur_top->data;
+	if (attrfork) {
+		if (!dip->di_anextents ||
+		    dip->di_aformat != XFS_DINODE_FMT_BTREE)
+			return 0;
+	} else {
+		if (!dip->di_nextents ||
+		    dip->di_format != XFS_DINODE_FMT_BTREE)
+			return 0;
+	}
+
+	ret = eval("push");
+	if (ret)
+		return ret;
+
+	if (dump_node_blocks) {
+		ret = eval("print %s.keys", prefix);
+		if (ret)
+			goto err;
+		ret = eval("print %s.ptrs", prefix);
+		if (ret)
+			goto err;
+	}
+
+	ret = eval("addr %s.ptrs[1]", prefix);
+	if (ret)
+		goto err;
+
+	ret = dump_btree(dump_node_blocks, true);
+	if (ret)
+		goto err;
+
+	ret = eval("pop");
+	return ret;
+err:
+	eval("pop");
+	return ret;
+}
+
+static int
+btdump_f(
+	int		argc,
+	char		**argv)
+{
+	bool		aflag = false;
+	bool		iflag = false;
+	int		c;
+
+	if (cur_typ == NULL) {
+		dbprintf(_("no current type\n"));
+		return 0;
+	}
+	while ((c = getopt(argc, argv, "ai")) != EOF) {
+		switch (c) {
+		case 'a':
+			aflag = true;
+			break;
+		case 'i':
+			iflag = true;
+			break;
+		default:
+			dbprintf(_("bad option for btdump command\n"));
+			return 0;
+		}
+	}
+	if (aflag && cur_typ->typnm != TYP_INODE) {
+		dbprintf(_("attrfork flag doesn't apply here\n"));
+		return 0;
+	}
+	switch (cur_typ->typnm) {
+	case TYP_BNOBT:
+	case TYP_CNTBT:
+	case TYP_INOBT:
+	case TYP_FINOBT:
+	case TYP_RMAPBT:
+	case TYP_REFCBT:
+		return dump_btree(iflag, false);
+	case TYP_BMAPBTA:
+	case TYP_BMAPBTD:
+		return dump_btree(iflag, true);
+	case TYP_INODE:
+		return dump_inode(iflag, aflag);
+	default:
+		dbprintf(_("Not a btree.\n"));
+		return 0;
+	}
+}
+
+static const cmdinfo_t btdump_cmd =
+	{ "btdump", "b", btdump_f, 0, 1, 0, "",
+	  N_("dump btree"), btdump_help };
+
+void
+btdump_init(void)
+{
+	add_command(&btdump_cmd);
+}
diff --git a/db/btdump.h b/db/btdump.h
new file mode 100644
index 0000000..45a65aa
--- /dev/null
+++ b/db/btdump.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
+ *
+ * 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	btdump_init(void);
diff --git a/db/command.c b/db/command.c
index 3d7cfd7..c2ed7b4 100644
--- a/db/command.c
+++ b/db/command.c
@@ -51,6 +51,7 @@
 #include "dquot.h"
 #include "fsmap.h"
 #include "crc.h"
+#include "btdump.h"
 
 cmdinfo_t	*cmdtab;
 int		ncmds;
@@ -124,6 +125,7 @@ init_commands(void)
 	attrset_init();
 	block_init();
 	bmap_init();
+	btdump_init();
 	check_init();
 	convert_init();
 	crc_init();

--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux