All of lore.kernel.org
 help / color / mirror / Atom feed
From: Su Yue <suy.fnst@cn.fujitsu.com>
To: Qu Wenruo <quwenruo.btrfs@gmx.com>, <linux-btrfs@vger.kernel.org>
Subject: Re: [PATCH] btrfs-progs: inspect-internal: add option '-k u64,u8,u64' of dump-tree
Date: Mon, 16 Jul 2018 16:14:43 +0800	[thread overview]
Message-ID: <b6dad5b4-6a37-5835-0491-19bda9aa7e5a@cn.fujitsu.com> (raw)
In-Reply-To: <556c8890-2908-7277-961f-8b5335179381@gmx.com>



On 07/16/2018 03:45 PM, Qu Wenruo wrote:
> 
> 
> On 2018年07月16日 13:55, Su Yue wrote:
>> 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.
> 
> Indeed a pretty useful debug oriented feature.
> 
>>
>> 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",
> 
> Shouldn't it conflict with -b and -r?
> 
>>   	"--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;
> 
> What about @key_set? @is_key_spec looks a little strange here.
> 
Ok, will call it is_spec_key_set in next version.

>>   
>>   	/*
>>   	 * 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'},
> 
> Small alignment mismatch, missing a space before "key".
> 
>>   			{ 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;
>>   	}
>>   
> 
> I really don't thing we need to put btrfS_print_spec_key() here.
> 
> It's in fact a special case, no need to nest it into the loop.
> Not to mention it appears 3 times in the main loop.
> 
Not understood what you mean.

>> @@ -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);
> 
> In fact, btrfs_print_tree() could replace all the following code.
> Which should further shrink the code size.
> 
Oh..just saw it, the code is copied and pasted from it though.

Thanks,
Su
> Thanks,
> Qu
> 
>> +		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
>>
> 
> 



  reply	other threads:[~2018-07-16  8:34 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2018-07-16  8:15     ` Qu Wenruo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b6dad5b4-6a37-5835-0491-19bda9aa7e5a@cn.fujitsu.com \
    --to=suy.fnst@cn.fujitsu.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=quwenruo.btrfs@gmx.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.