* [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.