All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] btrfs-progs: inspect-internal: add option '-k u64,u8,u64' of dump-tree
@ 2018-07-16  5:55 Su Yue
  2018-07-16  7:45 ` Qu Wenruo
  0 siblings, 1 reply; 4+ messages in thread
From: Su Yue @ 2018-07-16  5:55 UTC (permalink / raw)
  To: linux-btrfs; +Cc: suy.fnst

For big filesystems, there are many items in trees(extent tree
specially).
For example, to dump one extent, we usually dump extent tree then pipe
result to grep. The time-consuming part is that dump tree traverses
items. And it eats cpu and memory too.

This patch introduces an option '-k u64,u8,u64' for users(developer more
likely) to appoint a specific key to search and dump, then the path
from root node down the leaf will be dumped.
The search of the key costs most time of this way.

Signed-off-by: Su Yue <suy.fnst@cn.fujitsu.com>
---
In my experiment, not usual case though.
Image was provided by Chris Murphy, thanks.

#btrfs filesystem df /mnt
Data, single: total=767.00GiB, used=766.58GiB
System, DUP: total=32.00MiB, used=112.00KiB
Metadata, DUP: total=5.50GiB, used=4.69GiB
Metadata, single: total=16.00MiB, used=0.00B
GlobalReserve, single: total=512.00MiB, used=0.00B

Before:
#time bash -c 'btrfs inspect-internal dump-tree -t 2 ~/test/test.img | grep "1295194308608" >> /dev/null'
real    0m34.024s
user    0m3.269s
sys     0m4.047s

Patched and use -k:
#time bash -c './btrfs inspect-internal dump-tree -t 2  -k 1295194308608,0,0 ~/test/test.img >> /dev/null'

real    0m1.408s
user    0m0.006s
sys     0m0.014s

The new way is 34 times faster than 'grep' way, uses less memory and
cpu, and it prints path useful for debug.

---
 cmds-inspect-dump-tree.c |  54 +++++++++++++++++--
 print-tree.c             | 112 +++++++++++++++++++++++++++++++++++++++
 print-tree.h             |   2 +
 3 files changed, 163 insertions(+), 5 deletions(-)

diff --git a/cmds-inspect-dump-tree.c b/cmds-inspect-dump-tree.c
index c8acd55a0c3a..2a1a40c8270d 100644
--- a/cmds-inspect-dump-tree.c
+++ b/cmds-inspect-dump-tree.c
@@ -184,6 +184,21 @@ static u64 treeid_from_string(const char *str, const char **end)
 	return id;
 }
 
+static int parse_key(struct btrfs_key *key)
+{
+
+	int ret = sscanf(optarg, "%llu,%hhu,%llu", &key->objectid,
+			 &key->type, &key->offset);
+	if (ret != 3) {
+		error("error parsing key '%s'\n", optarg);
+		ret = -EINVAL;
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
 const char * const cmd_inspect_dump_tree_usage[] = {
 	"btrfs inspect-internal dump-tree [options] device",
 	"Dump tree structures from a given device",
@@ -199,6 +214,7 @@ const char * const cmd_inspect_dump_tree_usage[] = {
 	"-u|--uuid              print only the uuid tree",
 	"-b|--block <block_num> print info from the specified block only",
 	"-t|--tree <tree_id>    print only tree with the given id (string or number)",
+	"-k|--key <u64,u8,u64>  search the specific key then print path, must with -t",
 	"--follow               use with -b, to show all children tree blocks of <block_num>",
 	NULL
 };
@@ -224,8 +240,10 @@ int cmd_inspect_dump_tree(int argc, char **argv)
 	unsigned open_ctree_flags;
 	u64 block_only = 0;
 	struct btrfs_root *tree_root_scan;
+	struct btrfs_key spec_key = { 0 };
 	u64 tree_id = 0;
 	bool follow = false;
+	bool is_key_spec = false;
 
 	/*
 	 * For debug-tree, we care nothing about extent tree (it's just backref
@@ -248,10 +266,11 @@ int cmd_inspect_dump_tree(int argc, char **argv)
 			{ "block", required_argument, NULL, 'b'},
 			{ "tree", required_argument, NULL, 't'},
 			{ "follow", no_argument, NULL, GETOPT_VAL_FOLLOW },
+			{"key", required_argument, NULL, 'k'},
 			{ NULL, 0, NULL, 0 }
 		};
 
-		c = getopt_long(argc, argv, "deb:rRut:", long_options, NULL);
+		c = getopt_long(argc, argv, "deb:rRut:k:", long_options, NULL);
 		if (c < 0)
 			break;
 		switch (c) {
@@ -300,6 +319,12 @@ int cmd_inspect_dump_tree(int argc, char **argv)
 			}
 			break;
 			}
+		case 'k':
+			ret = parse_key(&spec_key);
+			if (ret)
+				exit(1);
+			is_key_spec = true;
+			break;
 		case GETOPT_VAL_FOLLOW:
 			follow = true;
 			break;
@@ -308,6 +333,9 @@ int cmd_inspect_dump_tree(int argc, char **argv)
 		}
 	}
 
+	if (!tree_id && is_key_spec)
+		usage(cmd_inspect_dump_tree_usage);
+
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_inspect_dump_tree_usage);
 
@@ -398,7 +426,11 @@ again:
 			goto close_root;
 		}
 		printf("root tree\n");
-		btrfs_print_tree(info->tree_root->node, 1);
+		if (is_key_spec)
+			btrfs_print_spec_key(info, BTRFS_ROOT_TREE_OBJECTID,
+					     &spec_key);
+		else
+			btrfs_print_tree(info->tree_root->node, 1);
 		goto close_root;
 	}
 
@@ -408,7 +440,11 @@ again:
 			goto close_root;
 		}
 		printf("chunk tree\n");
-		btrfs_print_tree(info->chunk_root->node, 1);
+		if (is_key_spec)
+			btrfs_print_spec_key(info, BTRFS_CHUNK_TREE_OBJECTID,
+					     &spec_key);
+		else
+			btrfs_print_tree(info->chunk_root->node, 1);
 		goto close_root;
 	}
 
@@ -418,7 +454,11 @@ again:
 			goto close_root;
 		}
 		printf("log root tree\n");
-		btrfs_print_tree(info->log_root_tree->node, 1);
+		if (is_key_spec)
+			btrfs_print_spec_key(info, BTRFS_TREE_LOG_OBJECTID,
+					     &spec_key);
+		else
+			btrfs_print_tree(info->log_root_tree->node, 1);
 		goto close_root;
 	}
 
@@ -564,7 +604,11 @@ again:
 					       btrfs_header_level(buf));
 				} else {
 					printf(" \n");
-					btrfs_print_tree(buf, 1);
+					if (is_key_spec)
+						btrfs_print_spec_key(info,
+						     found_key.objectid, &spec_key);
+					else
+						btrfs_print_tree(buf, 1);
 				}
 			}
 			free_extent_buffer(buf);
diff --git a/print-tree.c b/print-tree.c
index a09ecfbb28f0..f3a19fed8591 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -1459,3 +1459,115 @@ void btrfs_print_tree(struct extent_buffer *eb, int follow)
 
 	return;
 }
+
+void btrfs_print_spec_key(struct btrfs_fs_info *fs_info, u64 root_objectid,
+			  struct btrfs_key *skey)
+{
+	int i;
+	u32 nr;
+	u32 ptr_num;
+	int ret;
+	int level;
+	struct btrfs_root *root;
+	struct btrfs_disk_key disk_key;
+	struct btrfs_key key;
+	struct extent_buffer *next;
+	struct extent_buffer *eb;
+	struct btrfs_path path;
+
+	key.objectid = root_objectid;
+	key.type = BTRFS_ROOT_ITEM_KEY;
+	key.offset = (u64)-1;
+
+	if (key.objectid == BTRFS_TREE_RELOC_OBJECTID)
+		root = btrfs_read_fs_root_no_cache(fs_info, &key);
+	else
+		root = btrfs_read_fs_root(fs_info, &key);
+
+	if (IS_ERR(root) || !root) {
+		error("failed to read tree: %lld", key.objectid);
+		return;
+	}
+
+	btrfs_init_path(&path);
+	ret = btrfs_search_slot(NULL, root, skey, &path, 0, 0);
+	if (ret < 0) {
+		error("error search the key [%llu, %u, %llu] in root %llu",
+		      skey->objectid, skey->type, skey->offset, root->objectid);
+		goto out;
+	}
+
+	if (ret > 0) {
+		if (path.slots[0] > btrfs_header_nritems(path.nodes[0])) {
+			ret = btrfs_next_item(root, &path);
+			if (ret) {
+				error(
+	"error search the key [%llu, %u, %llu] in root %llu, no next key",
+					skey->objectid, skey->type,
+					skey->offset, root->objectid);
+				goto out;
+			}
+		}
+
+		btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+		printf("next to search key is [%llu, %u, %llu]\n",
+		       key.objectid, key.type, key.offset);
+	}
+
+	level = btrfs_header_level(root->node);
+	for (; level >= 0 ; --level) {
+		eb = path.nodes[level];
+		next = path.nodes[level - 1];
+		nr = btrfs_header_nritems(eb);
+		if (btrfs_is_leaf(eb)) {
+			btrfs_print_leaf(eb);
+			goto out;
+		}
+
+		/* We are crossing eb boundary, this node must be corrupted */
+		if (nr > BTRFS_NODEPTRS_PER_EXTENT_BUFFER(eb))
+			warning(
+		"node nr_items corrupted, has %u limit %u, continue anyway",
+				nr, BTRFS_NODEPTRS_PER_EXTENT_BUFFER(eb));
+		printf(
+		"node %llu level %d items %d free %u generation %llu owner ",
+		       (unsigned long long)eb->start,
+		       btrfs_header_level(eb), nr,
+		       (u32)BTRFS_NODEPTRS_PER_EXTENT_BUFFER(eb) - nr,
+		       (unsigned long long)btrfs_header_generation(eb));
+		print_objectid(stdout, btrfs_header_owner(eb), 0);
+		printf("\n");
+		print_uuids(eb);
+		fflush(stdout);
+		ptr_num = BTRFS_NODEPTRS_PER_EXTENT_BUFFER(eb);
+		for (i = 0; i < nr && i < ptr_num; i++) {
+			u64 blocknr = btrfs_node_blockptr(eb, i);
+
+			btrfs_node_key(eb, &disk_key, i);
+			btrfs_disk_key_to_cpu(&key, &disk_key);
+			printf("\t");
+			btrfs_print_key(&disk_key);
+			printf(" block %llu (%llu) gen %llu\n",
+			       (unsigned long long)blocknr,
+			       (unsigned long long)blocknr / eb->len,
+			       (unsigned long long)btrfs_node_ptr_generation(eb, i));
+			fflush(stdout);
+		}
+
+		if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) {
+			warning(
+				"eb corrupted: parent bytenr %llu slot %d level %d child bytenr %llu level has %d expect %d, skipping the slot",
+				btrfs_header_bytenr(eb), i,
+				btrfs_header_level(eb),
+				btrfs_header_bytenr(next),
+				btrfs_header_level(next),
+				btrfs_header_level(eb) - 1);
+			continue;
+		}
+	}
+
+out:
+	if (root_objectid == BTRFS_TREE_RELOC_OBJECTID)
+		btrfs_free_fs_root(root);
+	btrfs_release_path(&path);
+}
diff --git a/print-tree.h b/print-tree.h
index 62667d7f6195..94f231875a6c 100644
--- a/print-tree.h
+++ b/print-tree.h
@@ -26,4 +26,6 @@ void print_chunk_item(struct extent_buffer *eb, struct btrfs_chunk *chunk);
 void print_extent_item(struct extent_buffer *eb, int slot, int metadata);
 void print_objectid(FILE *stream, u64 objectid, u8 type);
 void print_key_type(FILE *stream, u64 objectid, u8 type);
+void btrfs_print_spec_key(struct btrfs_fs_info *info, u64 root_objectid,
+			  struct btrfs_key *key);
 #endif
-- 
2.17.1




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

end of thread, other threads:[~2018-07-16  8:41 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-16  5:55 [PATCH] btrfs-progs: inspect-internal: add option '-k u64,u8,u64' of dump-tree Su Yue
2018-07-16  7:45 ` Qu Wenruo
2018-07-16  8:14   ` Su Yue
2018-07-16  8:15     ` Qu Wenruo

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.