[PATCH v2 4/7] xfs_db: dump dir/attr btrees

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

 



Dump the directory or extended attribute btree contents.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
 db/btdump.c       |  255 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |    1 
 2 files changed, 255 insertions(+), 1 deletion(-)

diff --git a/db/btdump.c b/db/btdump.c
index 3b76e17..f525a4a 100644
--- a/db/btdump.c
+++ b/db/btdump.c
@@ -32,7 +32,9 @@ btdump_help(void)
 "\n"
 " If the cursor points to a btree block, 'btdump' dumps the btree\n"
 " downward from that block.  If the cursor points to an inode,\n"
-" the data fork btree root is selected by default.\n"
+" the data fork btree root is selected by default.  If the cursor\n"
+" points to a directory or extended attribute btree node, the tree\n"
+" will be printed downward from that block.\n"
 "\n"
 " Options:\n"
 "   -a -- Display an inode's extended attribute fork btree.\n"
@@ -227,6 +229,252 @@ dump_inode(
 	return ret;
 }
 
+static bool
+dir_has_rightsib(
+	void				*block,
+	int				level)
+{
+	struct xfs_dir3_icleaf_hdr	lhdr;
+	struct xfs_da3_icnode_hdr	nhdr;
+
+	if (level > 0) {
+		M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block);
+		return nhdr.forw != 0;
+	}
+	M_DIROPS(mp)->leaf_hdr_from_disk(&lhdr, block);
+	return lhdr.forw != 0;
+}
+
+static int
+dir_level(
+	void				*block)
+{
+	struct xfs_dir3_icleaf_hdr	lhdr;
+	struct xfs_da3_icnode_hdr	nhdr;
+
+	switch (((struct xfs_da_intnode *)block)->hdr.info.magic) {
+	case cpu_to_be16(XFS_DIR2_LEAF1_MAGIC):
+	case cpu_to_be16(XFS_DIR2_LEAFN_MAGIC):
+		M_DIROPS(mp)->leaf_hdr_from_disk(&lhdr, block);
+		return 0;
+	case cpu_to_be16(XFS_DA_NODE_MAGIC):
+		M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block);
+		return nhdr.level;
+	default:
+		return -1;
+	}
+}
+
+static int
+dir3_level(
+	void				*block)
+{
+	struct xfs_dir3_icleaf_hdr	lhdr;
+	struct xfs_da3_icnode_hdr	nhdr;
+
+	switch (((struct xfs_da_intnode *)block)->hdr.info.magic) {
+	case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC):
+	case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC):
+		M_DIROPS(mp)->leaf_hdr_from_disk(&lhdr, block);
+		return 0;
+	case cpu_to_be16(XFS_DA3_NODE_MAGIC):
+		M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block);
+		return nhdr.level;
+	default:
+		return -1;
+	}
+}
+
+static bool
+attr_has_rightsib(
+	void				*block,
+	int				level)
+{
+        struct xfs_attr_leafblock	lhdr;
+	struct xfs_da3_icnode_hdr	nhdr;
+
+	if (level > 0) {
+		M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block);
+		return nhdr.forw != 0;
+	}
+	xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, &lhdr, block);
+	return lhdr.hdr.info.forw != 0;
+}
+
+static int
+attr_level(
+	void				*block)
+{
+	struct xfs_attr_leafblock	lhdr;
+	struct xfs_da3_icnode_hdr	nhdr;
+
+	switch (((struct xfs_da_intnode *)block)->hdr.info.magic) {
+	case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
+		xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, &lhdr, block);
+		return 0;
+	case cpu_to_be16(XFS_DA_NODE_MAGIC):
+		M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block);
+		return nhdr.level;
+	default:
+		return -1;
+	}
+}
+
+static int
+attr3_level(
+	void				*block)
+{
+	struct xfs_attr_leafblock	lhdr;
+	struct xfs_da3_icnode_hdr	nhdr;
+
+	switch (((struct xfs_da_intnode *)block)->hdr.info.magic) {
+	case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
+		xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, &lhdr, block);
+		return 0;
+	case cpu_to_be16(XFS_DA3_NODE_MAGIC):
+		M_DIROPS(mp)->node_hdr_from_disk(&nhdr, block);
+		return nhdr.level;
+	default:
+		return -1;
+	}
+}
+
+struct dabprinter_ops {
+	const char		*print_node_entries;
+	const char		*print_leaf_entries;
+	const char		*go_node_forward;
+	const char		*go_leaf_forward;
+	const char		*go_down;
+	bool			(*has_rightsib)(void *, int);
+	int			(*level)(void *);
+};
+
+static struct dabprinter_ops attr_print = {
+	.print_node_entries	= "btree",
+	.print_leaf_entries	= "entries nvlist",
+	.go_node_forward	= "hdr.info.forw",
+	.go_leaf_forward	= "hdr.info.forw",
+	.go_down		= "btree[0].before",
+	.has_rightsib		= attr_has_rightsib,
+	.level			= attr_level,
+};
+
+static struct dabprinter_ops attr3_print = {
+	.print_node_entries	= "btree",
+	.print_leaf_entries	= "entries nvlist",
+	.go_node_forward	= "hdr.info.hdr.forw",
+	.go_leaf_forward	= "hdr.info.hdr.forw",
+	.go_down		= "btree[0].before",
+	.has_rightsib		= attr_has_rightsib,
+	.level			= attr3_level,
+};
+
+static struct dabprinter_ops dir_print = {
+	.print_node_entries	= "nbtree",
+	.print_leaf_entries	= "lents",
+	.go_node_forward	= "nhdr.info.hdr.forw",
+	.go_leaf_forward	= "lhdr.info.hdr.forw",
+	.go_down		= "nbtree[0].before",
+	.has_rightsib		= dir_has_rightsib,
+	.level			= dir_level,
+};
+
+static struct dabprinter_ops dir3_print = {
+	.print_node_entries	= "nbtree",
+	.print_leaf_entries	= "lents",
+	.go_node_forward	= "nhdr.info.forw",
+	.go_leaf_forward	= "lhdr.info.forw",
+	.go_down		= "nbtree[0].before",
+	.has_rightsib		= dir_has_rightsib,
+	.level			= dir3_level,
+};
+
+static int
+dump_dablevel(
+	int			level,
+	struct dabprinter_ops	*dbp)
+{
+	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);
+		ret = eval("print %s", level > 0 ? dbp->print_node_entries :
+						   dbp->print_leaf_entries);
+		if (ret)
+			goto err;
+		if (dbp->has_rightsib(iocur_top->data, level)) {
+			ret = eval("addr %s", level > 0 ? dbp->go_node_forward :
+							  dbp->go_leaf_forward);
+			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_dabtree(
+	bool				dump_node_blocks,
+	struct dabprinter_ops		*dbp)
+{
+	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 = dbp->level(iocur_top->data);
+	if (level < 0) {
+		printf(_("Current location is not part of a dir/attr btree.\n"));
+		goto err;
+	}
+
+	do {
+		last_daddr = iocur_top->bb;
+		if (level > 0) {
+			if (dump_node_blocks) {
+				ret = dump_dablevel(level, dbp);
+				if (ret)
+					goto err;
+			}
+			ret = eval("addr %s", dbp->go_down);
+		} else {
+			ret = dump_dablevel(level, dbp);
+		}
+		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
 btdump_f(
 	int		argc,
@@ -234,6 +482,7 @@ btdump_f(
 {
 	bool		aflag = false;
 	bool		iflag = false;
+	bool		crc = xfs_sb_version_hascrc(&mp->m_sb);
 	int		c;
 
 	if (cur_typ == NULL) {
@@ -276,6 +525,10 @@ btdump_f(
 		return dump_btree_long(iflag);
 	case TYP_INODE:
 		return dump_inode(iflag, aflag);
+	case TYP_ATTR:
+		return dump_dabtree(iflag, crc ? &attr3_print : &attr_print);
+	case TYP_DIR2:
+		return dump_dabtree(iflag, crc ? &dir3_print : &dir_print);
 	default:
 		dbprintf(_("type \"%s\" is not a btree type or inode\n"),
 				cur_typ->name);
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 6a97504..b3129f7 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -335,6 +335,7 @@ area of the inode, if neither option is given then both areas are shown.
 .B btdump [-a] [-i]
 If the cursor points to a btree node, dump the btree from that block downward.
 If instead the cursor points to an inode, dump the data fork block mapping btree if there is one.
+If the cursor points to a directory or extended attribute btree node, dump that.
 By default, only records stored in the btree are dumped.
 .RS 1.0i
 .TP 0.4i
--
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