All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v2] xfsprogs/db: add a command for dumping the btree blocks
@ 2017-04-11 14:37 Shan Hai
  2017-04-12  2:00 ` Shan Hai
  0 siblings, 1 reply; 2+ messages in thread
From: Shan Hai @ 2017-04-11 14:37 UTC (permalink / raw)
  To: linux-xfs

Currently there is no way to dump the whole blocks of btrees in the
xfs_db except manually step through the btree nodes, dumping the blocks
of the whole btree by a command is more convenient than interactive
walking of the tree in some circumstances.

This patch adds a new command to the xfs_db utility called 'treedump',
which can dump the specific btree or dump all btrees of the xfs, below
is an example usage of the command:

sudo xfs_db -r -c "agf 0" -c "addr bnoroot" -c "treedump" /dev/sda1

The blocks of the bnobt tree are dumped to the stdout.

Signed-off-by: Shan Hai <shan.hai@oracle.com>
---
 db/Makefile   |  10 +-
 db/command.c  |   2 +
 db/treedump.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 db/treedump.h |  21 ++++
 4 files changed, 389 insertions(+), 5 deletions(-)
 create mode 100644 db/treedump.c
 create mode 100644 db/treedump.h

diff --git a/db/Makefile b/db/Makefile
index cdc0b99..81eb4c4 100644
--- a/db/Makefile
+++ b/db/Makefile
@@ -8,11 +8,11 @@ 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 \
-	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 fsmap.h
+	btblock.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 sig.h strvec.h \
+	text.h treedump.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
 
diff --git a/db/command.c b/db/command.c
index 3d7cfd7..73568b5 100644
--- a/db/command.c
+++ b/db/command.c
@@ -46,6 +46,7 @@
 #include "print.h"
 #include "quit.h"
 #include "sb.h"
+#include "treedump.h"
 #include "write.h"
 #include "malloc.h"
 #include "dquot.h"
@@ -143,6 +144,7 @@ init_commands(void)
 	print_init();
 	quit_init();
 	sb_init();
+	treedump_init();
 	type_init();
 	write_init();
 	dquot_init();
diff --git a/db/treedump.c b/db/treedump.c
new file mode 100644
index 0000000..ee728da
--- /dev/null
+++ b/db/treedump.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2017 Oracle.
+ * All Rights Reserved.
+ *
+ * Author: Shan Hai <shan.hai@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.
+ *
+ * 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 "io.h"
+#include "type.h"
+#include "fprint.h"
+#include "faddr.h"
+#include "field.h"
+#include "input.h"
+#include "output.h"
+#include "init.h"
+
+static int
+treedump_f(
+	int			argc,
+	char			**argv);
+
+static void
+dump_level(
+	xfs_agnumber_t		agno,
+	struct xfs_btree_block  *block);
+
+static void
+dump_leaves(
+	xfs_agnumber_t		agno,
+	struct xfs_btree_block	*block);
+
+static void
+dump_btree(
+	xfs_agnumber_t		agno,
+	struct xfs_btree_block	*block);
+
+static void treedump_help(void);
+
+static const cmdinfo_t	treedump_cmd =
+	{ "treedump", NULL, treedump_f, 0, 2, 0,
+	  N_("[-d] [-a]"),
+	  N_("dump the btree blocks"), treedump_help };
+
+static void
+treedump_help(void)
+{
+	dbprintf(_(
+"\n"
+" 'treedump' prints the blocks of the specified filesystem btree\n"
+"\n"
+" Examples:\n"
+"\n"
+" agf agfno\n"
+" addr bnoroot\n"
+" treedump\n"
+"\n"
+" inode ino\n"
+" treedump -d (data fork)\n"
+" treedump -a (attr fork)\n"
+"\n"
+));
+
+}
+
+static void run_command(char *str)
+{
+	int	c;
+	char	**argv;
+	char	cmd[1024];
+
+	strcpy(cmd, str);
+	argv = breakline(cmd, &c);
+	command(c, argv);
+}
+
+static void 
+dump_fork(int	whichfork)
+{
+	xfs_fsblock_t		fsbno;
+	xfs_dinode_t		*dip;
+	xfs_bmdr_block_t	*dib;
+	xfs_bmdr_key_t		*kp;
+	xfs_bmdr_ptr_t		*pp;
+	int			level;
+	int			nrecs;
+	int			maxrecs;
+	int			i;
+	
+	dip = iocur_top->data;
+	dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
+	level = be16_to_cpu(dib->bb_level);
+	nrecs = be16_to_cpu(dib->bb_numrecs);
+	
+	maxrecs = libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0);
+	if (maxrecs <= 0) {
+		dbprintf(_("an empty (%s) fork in inode %lld\n"),
+			(whichfork == XFS_DATA_FORK) ? "data" : "attr",
+			(long long)iocur_top->ino);
+		return;
+	}
+
+	if (nrecs > maxrecs) {
+		dbprintf(_("invalid numrecs (%u) in inode %lld\n"),
+			 nrecs, (long long)iocur_top->ino);
+		return;
+	}
+
+	pp = XFS_BMDR_PTR_ADDR(dib, 1, maxrecs);
+
+	dbprintf(_("level = %d\n"), level);
+	dbprintf(_("keys[1-%d] = [startoff] "), nrecs);
+	for (i = 1; i <= nrecs; i++) {
+		kp = XFS_BMDR_KEY_ADDR(dib, i);
+		dbprintf(_("%d:[%ld] "), i, be64_to_cpu(kp->br_startoff));
+	}
+
+	dbprintf(_("\nptrs[1-%d] = "), nrecs);
+	for (i = 0; i < nrecs; i++)
+		dbprintf(_("%d:%ld "), i+1, be64_to_cpu(pp[i]));
+
+	dbprintf(_("\n"));
+
+	push_cur();
+	for (i = 0; i < nrecs; i++) {
+		fsbno = be64_to_cpu(pp[i]);
+		set_cur(&typtab[TYP_BMAPBTD], XFS_FSB_TO_DADDR(mp, fsbno),
+			blkbb, DB_RING_IGN, NULL);
+		if (!iocur_top->data) {
+			dbprintf(_("cannot read fsblock %lu\n"), fsbno);
+			return;
+		}
+		dump_btree(cur_agno, iocur_top->data);
+	}
+	pop_cur();
+}
+
+/* ARGSUSED */
+static int
+treedump_f(
+	int	argc,
+	char	**argv)
+{
+	int	c;
+	int	whichfork = -1;
+
+	if (!iocur_top->data) {
+		dbprintf(_("no btree/inode \n"));
+		return 0;
+	}
+
+	/* btrees except inode data/attr fork */
+	if (cur_typ->typnm != TYP_INODE) {
+		dump_btree(cur_agno, iocur_top->data);
+		return 0;
+	}
+
+	/* below is for inode data/attr fork */
+	while ((c = getopt(argc, argv, "ad")) != EOF) {
+		switch (c) {
+		case 'a':
+			whichfork = XFS_ATTR_FORK;
+			break;
+		case 'd':
+			whichfork = XFS_DATA_FORK;
+			break;
+		default:
+			dbprintf(_("bad option for treedump command\n"));
+			return 0;
+		}
+	}
+
+	/* all/empty options */
+	if (argc > 2 || whichfork < 0) {
+		dump_fork(XFS_DATA_FORK);
+		dump_fork(XFS_ATTR_FORK);
+	} else {
+		dump_fork(whichfork);
+	}
+
+	return 0;
+}
+
+void
+treedump_init(void)
+{
+	add_command(&treedump_cmd);
+}
+
+static void dump_level(
+	xfs_agnumber_t		agno,
+	struct xfs_btree_block	*block)
+{
+	xfs_agblock_t	agbno;
+	const typ_t	*typ = cur_typ;
+
+	run_command("print level keys ptrs");
+
+	push_cur();
+	for (;;) {
+		agbno = be32_to_cpu(block->bb_u.s.bb_rightsib);
+		if (agbno == NULLAGBLOCK)
+			break;
+
+		set_cur(&typtab[typ->typnm], XFS_AGB_TO_DADDR(mp, agno, agbno),
+			blkbb, DB_RING_IGN, NULL);
+
+		if (!iocur_top->data) {
+			dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
+			return;
+		}
+
+		run_command("print keys ptrs");
+
+		block = iocur_top->data;
+		typ = cur_typ;
+	}
+	pop_cur();
+}
+
+static void dump_leaves(
+	xfs_agnumber_t		agno,
+	struct xfs_btree_block	*block)
+{
+	xfs_agblock_t	agbno;
+	const typ_t	*typ = cur_typ;
+
+	for (;;) {
+		run_command("print level recs");
+
+		agbno = be32_to_cpu(block->bb_u.s.bb_rightsib);
+		if (agbno == NULLAGBLOCK)
+			break;
+
+		set_cur(&typtab[typ->typnm], XFS_AGB_TO_DADDR(mp, agno, agbno),
+			blkbb, DB_RING_IGN, NULL);
+
+		if (!iocur_top->data) {
+			dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
+			return;
+		}
+
+		block = iocur_top->data;
+		typ = cur_typ;
+	}
+}
+
+static void
+dump_btree(
+	xfs_agnumber_t		agno,
+	struct xfs_btree_block	*block)
+{
+	int			i;
+	const typ_t		*typ = cur_typ;
+	xfs_agblock_t		agbno = -1;
+	int 			level = be16_to_cpu(block->bb_level);
+	xfs_alloc_ptr_t		*allocp;
+	xfs_inobt_ptr_t		*inobtp;
+	xfs_refcount_ptr_t	*refcntp;
+	xfs_rmap_ptr_t          *rmapp;
+
+	int			magic;
+
+	for (i = level; i > 0; i--) {
+		dump_level(agno, block);
+
+		agbno = be32_to_cpu(block->bb_u.s.bb_leftsib);
+		if (agbno == NULLAGBLOCK)
+			break;
+
+		set_cur(&typtab[typ->typnm], XFS_AGB_TO_DADDR(mp, agno, agbno),
+			blkbb, DB_RING_IGN, NULL);
+
+		if (!iocur_top->data) {
+			dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
+			return;
+		}
+
+		block = iocur_top->data;
+		typ = cur_typ;
+	}
+
+	level = be16_to_cpu(block->bb_level);
+	magic = be32_to_cpu(block->bb_magic);
+
+	switch (magic) {
+	case XFS_ABTB_MAGIC:
+	case XFS_ABTB_CRC_MAGIC:
+	case XFS_ABTC_MAGIC:
+	case XFS_ABTC_CRC_MAGIC:
+		allocp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
+		agbno = be32_to_cpu(allocp[0]);
+		if (level > 0)
+			set_cur(&typtab[TYP_BNOBT],
+				XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb,
+				DB_RING_IGN, NULL);
+		break;
+	case XFS_BMAP_MAGIC:
+	case XFS_BMAP_CRC_MAGIC:
+		/* nothing */
+		break;
+	case XFS_FIBT_MAGIC:
+	case XFS_FIBT_CRC_MAGIC:
+		inobtp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
+		agbno = be32_to_cpu(inobtp[0]);
+		if (level > 0)
+			set_cur(&typtab[TYP_INOBT],
+				XFS_AGB_TO_DADDR(mp, agno, agbno),
+				blkbb, DB_RING_IGN, NULL);
+		break;
+	case XFS_IBT_MAGIC:
+	case XFS_IBT_CRC_MAGIC:
+		inobtp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
+		agbno = be32_to_cpu(inobtp[0]);
+		if (level > 0)
+			set_cur(&typtab[TYP_INOBT],
+				XFS_AGB_TO_DADDR(mp, agno, agbno),
+				blkbb, DB_RING_IGN, NULL);
+		break;
+	case XFS_REFC_CRC_MAGIC:
+		refcntp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]);
+		agbno = be32_to_cpu(refcntp[0]);
+		if (level > 0)
+			set_cur(&typtab[TYP_REFCBT],
+				XFS_AGB_TO_DADDR(mp, agno, agbno),
+				blkbb, DB_RING_IGN, NULL);
+		break;
+	case XFS_RMAP_CRC_MAGIC:
+		rmapp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
+		agbno = be32_to_cpu(rmapp[0]);
+		if (level > 0)
+			set_cur(&typtab[TYP_RMAPBT],
+				XFS_AGB_TO_DADDR(mp, agno, agbno),
+				blkbb, DB_RING_IGN, NULL);
+		break;
+	default:
+		dbprintf(_("bad magic number %u\n"), magic);
+		return;
+	}
+
+	if (!iocur_top->data) {
+		dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
+		return;
+	}
+	
+	dump_leaves(agno, iocur_top->data);
+}
diff --git a/db/treedump.h b/db/treedump.h
new file mode 100644
index 0000000..b8f31e4
--- /dev/null
+++ b/db/treedump.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017 Oracle.
+ * All Rights Reserved.
+ *
+ * Author: Shan Hai <shan.hai@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.
+ *
+ * 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	treedump_init(void);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [RFC PATCH v2] xfsprogs/db: add a command for dumping the btree blocks
  2017-04-11 14:37 [RFC PATCH v2] xfsprogs/db: add a command for dumping the btree blocks Shan Hai
@ 2017-04-12  2:00 ` Shan Hai
  0 siblings, 0 replies; 2+ messages in thread
From: Shan Hai @ 2017-04-12  2:00 UTC (permalink / raw)
  To: linux-xfs



On 2017年04月11日 22:37, Shan Hai wrote:
> Currently there is no way to dump the whole blocks of btrees in the
> xfs_db except manually step through the btree nodes, dumping the blocks
> of the whole btree by a command is more convenient than interactive
> walking of the tree in some circumstances.
>
> This patch adds a new command to the xfs_db utility called 'treedump',
> which can dump the specific btree or dump all btrees of the xfs, below
> is an example usage of the command:
>
> sudo xfs_db -r -c "agf 0" -c "addr bnoroot" -c "treedump" /dev/sda1
>
> The blocks of the bnobt tree are dumped to the stdout.
>
> Signed-off-by: Shan Hai <shan.hai@oracle.com>
> ---
>   db/Makefile   |  10 +-
>   db/command.c  |   2 +
>   db/treedump.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   db/treedump.h |  21 ++++
>   4 files changed, 389 insertions(+), 5 deletions(-)
>   create mode 100644 db/treedump.c
>   create mode 100644 db/treedump.h
>
> diff --git a/db/Makefile b/db/Makefile
> index cdc0b99..81eb4c4 100644
> --- a/db/Makefile
> +++ b/db/Makefile
> @@ -8,11 +8,11 @@ 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 \
> -	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 fsmap.h
> +	btblock.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 sig.h strvec.h \
> +	text.h treedump.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
>   
> diff --git a/db/command.c b/db/command.c
> index 3d7cfd7..73568b5 100644
> --- a/db/command.c
> +++ b/db/command.c
> @@ -46,6 +46,7 @@
>   #include "print.h"
>   #include "quit.h"
>   #include "sb.h"
> +#include "treedump.h"
>   #include "write.h"
>   #include "malloc.h"
>   #include "dquot.h"
> @@ -143,6 +144,7 @@ init_commands(void)
>   	print_init();
>   	quit_init();
>   	sb_init();
> +	treedump_init();
>   	type_init();
>   	write_init();
>   	dquot_init();
> diff --git a/db/treedump.c b/db/treedump.c
> new file mode 100644
> index 0000000..ee728da
> --- /dev/null
> +++ b/db/treedump.c
> @@ -0,0 +1,361 @@
> +/*
> + * Copyright (c) 2017 Oracle.
> + * All Rights Reserved.
> + *
> + * Author: Shan Hai <shan.hai@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.
> + *
> + * 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 "io.h"
> +#include "type.h"
> +#include "fprint.h"
> +#include "faddr.h"
> +#include "field.h"
> +#include "input.h"
> +#include "output.h"
> +#include "init.h"
> +
> +static int
> +treedump_f(
> +	int			argc,
> +	char			**argv);
> +
> +static void
> +dump_level(
> +	xfs_agnumber_t		agno,
> +	struct xfs_btree_block  *block);
> +
> +static void
> +dump_leaves(
> +	xfs_agnumber_t		agno,
> +	struct xfs_btree_block	*block);
> +
> +static void
> +dump_btree(
> +	xfs_agnumber_t		agno,
> +	struct xfs_btree_block	*block);
> +
> +static void treedump_help(void);
> +
> +static const cmdinfo_t	treedump_cmd =
> +	{ "treedump", NULL, treedump_f, 0, 2, 0,
> +	  N_("[-d] [-a]"),
> +	  N_("dump the btree blocks"), treedump_help };
> +
> +static void
> +treedump_help(void)
> +{
> +	dbprintf(_(
> +"\n"
> +" 'treedump' prints the blocks of the specified filesystem btree\n"
> +"\n"
> +" Examples:\n"
> +"\n"
> +" agf agfno\n"
> +" addr bnoroot\n"
> +" treedump\n"
> +"\n"
> +" inode ino\n"
> +" treedump -d (data fork)\n"
> +" treedump -a (attr fork)\n"
> +"\n"
> +));
> +
> +}
> +
> +static void run_command(char *str)
> +{
> +	int	c;
> +	char	**argv;
> +	char	cmd[1024];
> +
> +	strcpy(cmd, str);
> +	argv = breakline(cmd, &c);
> +	command(c, argv);
> +}
> +
> +static void
> +dump_fork(int	whichfork)
> +{
> +	xfs_fsblock_t		fsbno;
> +	xfs_dinode_t		*dip;
> +	xfs_bmdr_block_t	*dib;
> +	xfs_bmdr_key_t		*kp;
> +	xfs_bmdr_ptr_t		*pp;
> +	int			level;
> +	int			nrecs;
> +	int			maxrecs;
> +	int			i;
> +	
> +	dip = iocur_top->data;
> +	dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
> +	level = be16_to_cpu(dib->bb_level);
> +	nrecs = be16_to_cpu(dib->bb_numrecs);
> +	
> +	maxrecs = libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0);
> +	if (maxrecs <= 0) {
> +		dbprintf(_("an empty (%s) fork in inode %lld\n"),
> +			(whichfork == XFS_DATA_FORK) ? "data" : "attr",
> +			(long long)iocur_top->ino);
> +		return;
> +	}
> +
> +	if (nrecs > maxrecs) {
> +		dbprintf(_("invalid numrecs (%u) in inode %lld\n"),
> +			 nrecs, (long long)iocur_top->ino);
> +		return;
> +	}
> +
> +	pp = XFS_BMDR_PTR_ADDR(dib, 1, maxrecs);
> +
> +	dbprintf(_("level = %d\n"), level);
> +	dbprintf(_("keys[1-%d] = [startoff] "), nrecs);
> +	for (i = 1; i <= nrecs; i++) {
> +		kp = XFS_BMDR_KEY_ADDR(dib, i);
> +		dbprintf(_("%d:[%ld] "), i, be64_to_cpu(kp->br_startoff));
> +	}
> +
> +	dbprintf(_("\nptrs[1-%d] = "), nrecs);
> +	for (i = 0; i < nrecs; i++)
> +		dbprintf(_("%d:%ld "), i+1, be64_to_cpu(pp[i]));
> +
> +	dbprintf(_("\n"));
> +
> +	push_cur();
> +	for (i = 0; i < nrecs; i++) {
> +		fsbno = be64_to_cpu(pp[i]);
> +		set_cur(&typtab[TYP_BMAPBTD], XFS_FSB_TO_DADDR(mp, fsbno),
> +			blkbb, DB_RING_IGN, NULL);
> +		if (!iocur_top->data) {
> +			dbprintf(_("cannot read fsblock %lu\n"), fsbno);
> +			return;
> +		}
> +		dump_btree(cur_agno, iocur_top->data);
> +	}
> +	pop_cur();
> +}
> +
> +/* ARGSUSED */
> +static int
> +treedump_f(
> +	int	argc,
> +	char	**argv)
> +{
> +	int	c;
> +	int	whichfork = -1;
> +
> +	if (!iocur_top->data) {
> +		dbprintf(_("no btree/inode \n"));
> +		return 0;
> +	}
> +
> +	/* btrees except inode data/attr fork */
> +	if (cur_typ->typnm != TYP_INODE) {
> +		dump_btree(cur_agno, iocur_top->data);
> +		return 0;
> +	}
> +
> +	/* below is for inode data/attr fork */
> +	while ((c = getopt(argc, argv, "ad")) != EOF) {
> +		switch (c) {
> +		case 'a':
> +			whichfork = XFS_ATTR_FORK;
> +			break;
> +		case 'd':
> +			whichfork = XFS_DATA_FORK;
> +			break;
> +		default:
> +			dbprintf(_("bad option for treedump command\n"));
> +			return 0;
> +		}
> +	}
> +
> +	/* all/empty options */
> +	if (argc > 2 || whichfork < 0) {
> +		dump_fork(XFS_DATA_FORK);
> +		dump_fork(XFS_ATTR_FORK);
> +	} else {
> +		dump_fork(whichfork);
> +	}
> +
> +	return 0;
> +}
> +
> +void
> +treedump_init(void)
> +{
> +	add_command(&treedump_cmd);
> +}
> +
> +static void dump_level(
> +	xfs_agnumber_t		agno,
> +	struct xfs_btree_block	*block)
> +{
> +	xfs_agblock_t	agbno;
> +	const typ_t	*typ = cur_typ;
> +
> +	run_command("print level keys ptrs");
> +
> +	push_cur();
> +	for (;;) {
> +		agbno = be32_to_cpu(block->bb_u.s.bb_rightsib);
> +		if (agbno == NULLAGBLOCK)
> +			break;
> +
> +		set_cur(&typtab[typ->typnm], XFS_AGB_TO_DADDR(mp, agno, agbno),
> +			blkbb, DB_RING_IGN, NULL);
> +
> +		if (!iocur_top->data) {
> +			dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
> +			return;
> +		}
> +
> +		run_command("print keys ptrs");
> +
> +		block = iocur_top->data;
> +		typ = cur_typ;
> +	}
> +	pop_cur();
> +}
> +
> +static void dump_leaves(
> +	xfs_agnumber_t		agno,
> +	struct xfs_btree_block	*block)
> +{
> +	xfs_agblock_t	agbno;
> +	const typ_t	*typ = cur_typ;
> +
> +	for (;;) {
> +		run_command("print level recs");
> +
> +		agbno = be32_to_cpu(block->bb_u.s.bb_rightsib);
> +		if (agbno == NULLAGBLOCK)
> +			break;
> +
> +		set_cur(&typtab[typ->typnm], XFS_AGB_TO_DADDR(mp, agno, agbno),
> +			blkbb, DB_RING_IGN, NULL);
> +
> +		if (!iocur_top->data) {
> +			dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
> +			return;
> +		}
> +
> +		block = iocur_top->data;
> +		typ = cur_typ;
> +	}
> +}
> +
> +static void
> +dump_btree(
> +	xfs_agnumber_t		agno,
> +	struct xfs_btree_block	*block)
> +{
> +	int			i;
> +	const typ_t		*typ = cur_typ;
> +	xfs_agblock_t		agbno = -1;
> +	int 			level = be16_to_cpu(block->bb_level);
> +	xfs_alloc_ptr_t		*allocp;
> +	xfs_inobt_ptr_t		*inobtp;
> +	xfs_refcount_ptr_t	*refcntp;
> +	xfs_rmap_ptr_t          *rmapp;
> +
> +	int			magic;
> +
> +	for (i = level; i > 0; i--) {
> +		dump_level(agno, block);
> +
> +		agbno = be32_to_cpu(block->bb_u.s.bb_leftsib);
> +		if (agbno == NULLAGBLOCK)
> +			break;
> +

Oops, should walk down a level, fix it in the v3 patch.

Thanks
Shan Hai

> +		set_cur(&typtab[typ->typnm], XFS_AGB_TO_DADDR(mp, agno, agbno),
> +			blkbb, DB_RING_IGN, NULL);
> +
> +		if (!iocur_top->data) {
> +			dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
> +			return;
> +		}
> +
> +		block = iocur_top->data;
> +		typ = cur_typ;
> +	}
> +
> +	level = be16_to_cpu(block->bb_level);
> +	magic = be32_to_cpu(block->bb_magic);
> +
> +	switch (magic) {
> +	case XFS_ABTB_MAGIC:
> +	case XFS_ABTB_CRC_MAGIC:
> +	case XFS_ABTC_MAGIC:
> +	case XFS_ABTC_CRC_MAGIC:
> +		allocp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
> +		agbno = be32_to_cpu(allocp[0]);
> +		if (level > 0)
> +			set_cur(&typtab[TYP_BNOBT],
> +				XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb,
> +				DB_RING_IGN, NULL);
> +		break;
> +	case XFS_BMAP_MAGIC:
> +	case XFS_BMAP_CRC_MAGIC:
> +		/* nothing */
> +		break;
> +	case XFS_FIBT_MAGIC:
> +	case XFS_FIBT_CRC_MAGIC:
> +		inobtp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
> +		agbno = be32_to_cpu(inobtp[0]);
> +		if (level > 0)
> +			set_cur(&typtab[TYP_INOBT],
> +				XFS_AGB_TO_DADDR(mp, agno, agbno),
> +				blkbb, DB_RING_IGN, NULL);
> +		break;
> +	case XFS_IBT_MAGIC:
> +	case XFS_IBT_CRC_MAGIC:
> +		inobtp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
> +		agbno = be32_to_cpu(inobtp[0]);
> +		if (level > 0)
> +			set_cur(&typtab[TYP_INOBT],
> +				XFS_AGB_TO_DADDR(mp, agno, agbno),
> +				blkbb, DB_RING_IGN, NULL);
> +		break;
> +	case XFS_REFC_CRC_MAGIC:
> +		refcntp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]);
> +		agbno = be32_to_cpu(refcntp[0]);
> +		if (level > 0)
> +			set_cur(&typtab[TYP_REFCBT],
> +				XFS_AGB_TO_DADDR(mp, agno, agbno),
> +				blkbb, DB_RING_IGN, NULL);
> +		break;
> +	case XFS_RMAP_CRC_MAGIC:
> +		rmapp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
> +		agbno = be32_to_cpu(rmapp[0]);
> +		if (level > 0)
> +			set_cur(&typtab[TYP_RMAPBT],
> +				XFS_AGB_TO_DADDR(mp, agno, agbno),
> +				blkbb, DB_RING_IGN, NULL);
> +		break;
> +	default:
> +		dbprintf(_("bad magic number %u\n"), magic);
> +		return;
> +	}
> +
> +	if (!iocur_top->data) {
> +		dbprintf(_("cannot read block %u/%u\n"), agno, agbno);
> +		return;
> +	}
> +	
> +	dump_leaves(agno, iocur_top->data);
> +}
> diff --git a/db/treedump.h b/db/treedump.h
> new file mode 100644
> index 0000000..b8f31e4
> --- /dev/null
> +++ b/db/treedump.h
> @@ -0,0 +1,21 @@
> +/*
> + * Copyright (c) 2017 Oracle.
> + * All Rights Reserved.
> + *
> + * Author: Shan Hai <shan.hai@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.
> + *
> + * 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	treedump_init(void);


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-04-12  2:00 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-11 14:37 [RFC PATCH v2] xfsprogs/db: add a command for dumping the btree blocks Shan Hai
2017-04-12  2:00 ` Shan Hai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.