linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Qu Wenruo <quwenruo@cn.fujitsu.com>
To: linux-btrfs@vger.kernel.org
Cc: Qu Wenruo <quwenruo@cn.fujitsu.com>
Subject: Re: [PATCH] btrfs-progs: Add chunk corrupt funtion to btrfs-corrupt-block
Date: Wed, 17 Jul 2013 08:34:44 +0800	[thread overview]
Message-ID: <51E5E6A4.40409@cn.fujitsu.com> (raw)
In-Reply-To: <1370571959-13715-1-git-send-email-quwenruo@cn.fujitsu.com>

Since the new chunk recovery patches are merged,
what about merging this patch to add chunk corruption function? :)

Qu

于 2013年06月07日 10:25, Qu Wenruo 写道:
> Add chunk corrupt function to btrfs-corrupt-block.
> This funtion can be used to delete or corrupt a given chunk or the whole
> chunk tree.
>
> This funtion is useful to test the coming chunk recover funtion.
>
> BTW, since the chunk recover funtion is based on whole partion scanning,
> so the COW should be disabled and edit leaf without changing generation.
> Which makes btrfs_commit_transation giving some ignorable warning.
>
> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
> ---
>  btrfs-corrupt-block.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 201 insertions(+), 17 deletions(-)
>
> diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
> index 8176fad..481b7b8 100644
> --- a/btrfs-corrupt-block.c
> +++ b/btrfs-corrupt-block.c
> @@ -58,8 +58,9 @@ struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr,
>  		device->total_ios++;
>  		eb->dev_bytenr = multi->stripes[0].physical;
>  
> -		fprintf(stdout, "mirror %d logical %Lu physical %Lu "
> -			"device %s\n", mirror_num, (unsigned long long)bytenr,
> +		fprintf(stdout,
> +			"mirror %d logical %llu physical %llu device %s\n",
> +			mirror_num, (unsigned long long)bytenr,
>  			(unsigned long long)eb->dev_bytenr, device->name);
>  		kfree(multi);
>  
> @@ -92,7 +93,9 @@ static void print_usage(void)
>  		" (usually 1 or 2, default: 0)\n");
>  	fprintf(stderr, "\t-b Number of bytes to be corrupted\n");
>  	fprintf(stderr, "\t-e Extent to be corrupted\n");
> -	fprintf(stderr, "\t-E The whole extent free to be corrupted\n");
> +	fprintf(stderr, "\t-E The whole extent tree to be corrupted\n");
> +	fprintf(stderr, "\t-u Given chunk item to be corrupted\n");
> +	fprintf(stderr, "\t-U The whole chunk tree to be corrupted\n");
>  	exit(1);
>  }
>  
> @@ -115,7 +118,8 @@ static void corrupt_keys(struct btrfs_trans_handle *trans,
>  	if (bad_slot == slot)
>  		return;
>  
> -	fprintf(stderr, "corrupting keys in block %llu slot %d swapping with %d\n",
> +	fprintf(stderr,
> +		"corrupting keys in block %llu slot %d swapping with %d\n",
>  		(unsigned long long)eb->start, slot, bad_slot);
>  
>  	if (btrfs_header_level(eb) == 0) {
> @@ -191,7 +195,8 @@ static int corrupt_extent(struct btrfs_trans_handle *trans,
>  			goto next;
>  
>  		if (should_del) {
> -			fprintf(stderr, "deleting extent record: key %Lu %u %Lu\n",
> +			fprintf(stderr,
> +				"deleting extent record: key %llu %u %llu\n",
>  				key.objectid, key.type, key.offset);
>  
>  			if (key.type == BTRFS_EXTENT_ITEM_KEY) {
> @@ -203,7 +208,8 @@ static int corrupt_extent(struct btrfs_trans_handle *trans,
>  
>  			btrfs_del_item(trans, root, path);
>  		} else {
> -			fprintf(stderr, "corrupting extent record: key %Lu %u %Lu\n",
> +			fprintf(stderr,
> +				"corrupting extent record: key %llu %u %llu\n",
>  				key.objectid, key.type, key.offset);
>  			ptr = btrfs_item_ptr_offset(leaf, slot);
>  			item_size = btrfs_item_size_nr(leaf, slot);
> @@ -224,7 +230,8 @@ next:
>  }
>  
>  static void btrfs_corrupt_extent_leaf(struct btrfs_trans_handle *trans,
> -				      struct btrfs_root *root, struct extent_buffer *eb)
> +				      struct btrfs_root *root,
> +				      struct extent_buffer *eb)
>  {
>  	u32 nr = btrfs_header_nritems(eb);
>  	u32 victim = rand() % nr;
> @@ -237,7 +244,8 @@ static void btrfs_corrupt_extent_leaf(struct btrfs_trans_handle *trans,
>  }
>  
>  static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
> -				      struct btrfs_root *root, struct extent_buffer *eb)
> +				      struct btrfs_root *root,
> +				      struct extent_buffer *eb)
>  {
>  	int i;
>  	u32 nr;
> @@ -260,7 +268,8 @@ static void btrfs_corrupt_extent_tree(struct btrfs_trans_handle *trans,
>  		struct extent_buffer *next;
>  
>  		next = read_tree_block(root, btrfs_node_blockptr(eb, i),
> -				       root->leafsize, btrfs_node_ptr_generation(eb, i));
> +				       root->leafsize,
> +				       btrfs_node_ptr_generation(eb, i));
>  		if (!next)
>  			continue;
>  		btrfs_corrupt_extent_tree(trans, root, next);
> @@ -276,17 +285,159 @@ static struct option long_options[] = {
>  	{ "extent-record", 0, NULL, 'e' },
>  	{ "extent-tree", 0, NULL, 'E' },
>  	{ "keys", 0, NULL, 'k' },
> +	{ "chunk-record", 0, NULL, 'u' },
> +	{ "chunk-tree", 0, NULL, 'U' },
>  	{ 0, 0, 0, 0}
>  };
>  
> +/* corrupt item using NO cow.
> + * Because chunk recover will recover based on whole partition scaning,
> + * If using COW, chunk recover will use the old item to recover,
> + * which is still OK but we want to check the ability to rebuild chunk
> + * not only restore the old ones */
> +int corrupt_item_nocow(struct btrfs_trans_handle *trans,
> +		       struct btrfs_root *root, struct btrfs_path *path,
> +		       int del)
> +{
> +	int ret = 0;
> +	struct btrfs_key key;
> +	struct extent_buffer *leaf;
> +	unsigned long ptr;
> +	int slot;
> +	u32 item_size;
>  
> +	leaf = path->nodes[0];
> +	slot = path->slots[0];
> +	/* Not deleting the first item of a leaf to keep leaf structure */
> +	if (slot == 0)
> +		del = 0;
> +	/* Only accept valid eb */
> +	BUG_ON(!leaf->data || slot >= btrfs_header_nritems(leaf));
> +	btrfs_item_key_to_cpu(leaf, &key, slot);
> +	if (del) {
> +		fprintf(stdout, "Deleting key and data [%llu, %u, %llu].\n",
> +			key.objectid, key.type, key.offset);
> +		btrfs_del_item(trans, root, path);
> +	} else {
> +		fprintf(stdout, "Corrupting key and data [%llu, %u, %llu].\n",
> +			key.objectid, key.type, key.offset);
> +		ptr = btrfs_item_ptr_offset(leaf, slot);
> +		item_size = btrfs_item_size_nr(leaf, slot);
> +		memset_extent_buffer(leaf, 0, ptr, item_size);
> +		btrfs_mark_buffer_dirty(leaf);
> +	}
> +	return ret;
> +}
> +int corrupt_chunk_tree(struct btrfs_trans_handle *trans,
> +		       struct btrfs_root *root)
> +{
> +	int ret;
> +	int del;
> +	int slot;
> +	struct btrfs_path *path;
> +	struct btrfs_key key;
> +	struct btrfs_key found_key;
> +	struct extent_buffer *leaf;
> +
> +	path = btrfs_alloc_path();
> +	key.objectid = (u64)-1;
> +	key.offset = (u64)-1;
> +	key.type = (u8)-1;
> +
> +	/* Here, cow and ins_len must equals 0 for the following reasons:
> +	 * 1) chunk recover is based on disk scanning, so COW should be
> +	 *    disabled in case the original chunk being scanned and
> +	 *    recovered using the old chunk.
> +	 * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
> +	 *    triggered.
> +	 */
> +	ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
> +	BUG_ON(ret == 0);
> +	if (ret < 0) {
> +		fprintf(stderr, "Error searching tree\n");
> +		goto free_out;
> +	}
> +	/* corrupt/del dev_item first */
> +	while (!btrfs_previous_item(root, path, 0, BTRFS_DEV_ITEM_KEY)) {
> +		slot = path->slots[0];
> +		leaf = path->nodes[0];
> +		del = rand() % 3;
> +		/* Never delete the first item to keep the leaf structure */
> +		if (path->slots[0] == 0)
> +			del = 0;
> +		ret = corrupt_item_nocow(trans, root, path, del);
> +		if (ret)
> +			goto free_out;
> +	}
> +	btrfs_free_path(path);
> +
> +	/* Here, cow and ins_len must equals 0 for the following reasons:
> +	 * 1) chunk recover is based on disk scanning, so COW should be
> +	 *    disabled in case the original chunk being scanned and
> +	 *    recovered using the old chunk.
> +	 * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON will be
> +	 *    triggered.
> +	 */
> +	path = btrfs_alloc_path();
> +	ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
> +	BUG_ON(ret == 0);
> +	if (ret < 0) {
> +		fprintf(stderr, "Error searching tree\n");
> +		goto free_out;
> +	}
> +	/* corrupt/del chunk then*/
> +	while (!btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY)) {
> +		slot = path->slots[0];
> +		leaf = path->nodes[0];
> +		del = rand() % 3;
> +		btrfs_item_key_to_cpu(leaf, &found_key, slot);
> +		ret = corrupt_item_nocow(trans, root, path, del);
> +		if (ret)
> +			goto free_out;
> +	}
> +free_out:
> +	btrfs_free_path(path);
> +	return ret;
> +}
> +int find_chunk_offset(struct btrfs_root *root,
> +		      struct btrfs_path *path, u64 offset)
> +{
> +	struct btrfs_key key;
> +	int ret;
> +
> +	key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
> +	key.type = BTRFS_CHUNK_ITEM_KEY;
> +	key.offset = offset;
> +
> +	/* Here, cow and ins_len must equals 0 for following reasons:
> +	 * 1) chunk recover is based on disk scanning, so COW should
> +	 *    be disabled in case the original chunk being scanned
> +	 *    and recovered using the old chunk.
> +	 * 2) if cow = 0, ins_len must also be set to 0, or BUG_ON
> +	 *    will be triggered.
> +	 */
> +	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
> +	if (ret > 0) {
> +		fprintf(stderr, "Can't find chunk with given offset %llu\n",
> +			offset);
> +		goto out;
> +	}
> +	if (ret < 0) {
> +		fprintf(stderr, "Error searching chunk");
> +		goto out;
> +	}
> +out:
> +	return ret;
> +
> +}
>  int main(int ac, char **av)
>  {
>  	struct cache_tree root_cache;
>  	struct btrfs_root *root;
>  	struct extent_buffer *eb;
>  	char *dev;
> -	u64 logical = 0;
> +	/* chunk offset can be 0,so change to (u64)-1 */
> +	u64 logical = (u64)-1;
>  	int ret = 0;
>  	int option_index = 0;
>  	int copy = 0;
> @@ -294,23 +445,20 @@ int main(int ac, char **av)
>  	int extent_rec = 0;
>  	int extent_tree = 0;
>  	int corrupt_block_keys = 0;
> +	int chunk_rec = 0;
> +	int chunk_tree = 0;
>  
>  	srand(128);
>  
>  	while(1) {
>  		int c;
> -		c = getopt_long(ac, av, "l:c:b:eEk", long_options,
> +		c = getopt_long(ac, av, "l:c:b:eEkuU", long_options,
>  				&option_index);
>  		if (c < 0)
>  			break;
>  		switch(c) {
>  			case 'l':
>  				logical = atoll(optarg);
> -				if (logical == 0) {
> -					fprintf(stderr,
> -						"invalid extent number\n");
> -					print_usage();
> -				}
>  				break;
>  			case 'c':
>  				copy = atoi(optarg);
> @@ -337,6 +485,12 @@ int main(int ac, char **av)
>  			case 'k':
>  				corrupt_block_keys = 1;
>  				break;
> +			case 'u':
> +				chunk_rec = 1;
> +				break;
> +			case 'U':
> +				chunk_tree = 1;
> +				break;
>  			default:
>  				print_usage();
>  		}
> @@ -344,7 +498,7 @@ int main(int ac, char **av)
>  	ac = ac - optind;
>  	if (ac == 0)
>  		print_usage();
> -	if (logical == 0 && !extent_tree)
> +	if (logical == (u64)-1 && !(extent_tree || chunk_tree))
>  		print_usage();
>  	if (copy < 0)
>  		print_usage();
> @@ -374,6 +528,36 @@ int main(int ac, char **av)
>  		btrfs_commit_transaction(trans, root);
>  		goto out_close;
>  	}
> +	if (chunk_rec) {
> +		struct btrfs_trans_handle *trans;
> +		struct btrfs_path *path;
> +		int del;
> +
> +		del = rand() % 3;
> +		path = btrfs_alloc_path();
> +
> +		if (find_chunk_offset(root->fs_info->chunk_root, path,
> +				      logical) != 0) {
> +			btrfs_free_path(path);
> +			goto out_close;
> +		}
> +		trans = btrfs_start_transaction(root, 1);
> +		ret = corrupt_item_nocow(trans, root->fs_info->chunk_root,
> +					 path, del);
> +		if (ret < 0)
> +			fprintf(stderr, "Failed to corrupt chunk record\n");
> +		btrfs_commit_transaction(trans, root);
> +		goto out_close;
> +	}
> +	if (chunk_tree) {
> +		struct btrfs_trans_handle *trans;
> +		trans = btrfs_start_transaction(root, 1);
> +		ret = corrupt_chunk_tree(trans, root->fs_info->chunk_root);
> +		if (ret < 0)
> +			fprintf(stderr, "Failed to corrupt chunk tree\n");
> +		btrfs_commit_transaction(trans, root);
> +		goto out_close;
> +	}
>  
>  	if (bytes == 0)
>  		bytes = root->sectorsize;


-- 
-----------------------------------------------------
Qu Wenruo
Development Dept.I
Nanjing Fujitsu Nanda Software Tech. Co., Ltd.(FNST)
No. 6 Wenzhu Road, Nanjing, 210012, China
TEL: +86+25-86630566-8526
COINS: 7998-8526
FAX: +86+25-83317685
MAIL: quwenruo@cn.fujitsu.com
-----------------------------------------------------


      reply	other threads:[~2013-07-17  0:34 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-07  2:25 [PATCH] btrfs-progs: Add chunk corrupt funtion to btrfs-corrupt-block Qu Wenruo
2013-07-17  0:34 ` Qu Wenruo [this message]

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=51E5E6A4.40409@cn.fujitsu.com \
    --to=quwenruo@cn.fujitsu.com \
    --cc=linux-btrfs@vger.kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).