linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Qu Wenruo <quwenruo.btrfs@gmx.com>
To: Nikolay Borisov <nborisov@suse.com>, Qu Wenruo <wqu@suse.com>,
	linux-btrfs@vger.kernel.org
Subject: Re: [PATCH 1/3] btrfs: tree-checker: Add EXTENT_ITEM and METADATA_ITEM check
Date: Mon, 29 Jul 2019 21:53:10 +0800	[thread overview]
Message-ID: <66256780-4fa9-9627-151e-62e834a6cc39@gmx.com> (raw)
In-Reply-To: <bd6c75f8-c9b5-c29f-a691-101fee33cef5@suse.com>



On 2019/7/29 下午9:42, Nikolay Borisov wrote:
[...]
>> +
>> +	/* key->offset is tree level for METADATA_ITEM_KEY */
>> +	if (key->type == BTRFS_METADATA_ITEM_KEY) {
>> +		if (key->offset >= BTRFS_MAX_LEVEL) {
>
> make it a compound statement:
>
> if key->type && key->offset. The extra if doesn't bring anything...

Right, that's the case.
I though there would be more checks, but turns out there is only one check.

>
>> +			extent_err(leaf, slot,
>> +				"invalid tree level, have %llu expect [0, %u]",
>> +				   key->offset, BTRFS_MAX_LEVEL - 1);
>> +			return -EUCLEAN;
>> +		}
>> +	}
>> +
>> +	/*
>> +	 * EXTENT/METADATA_ITEM is consistent of:
>> +	 * 1) One btrfs_extent_item
>> +	 *    Records the total refs, type and generation of the extent.
>> +	 *
>> +	 * 2) One btrfs_tree_block_info (for EXTENT_ITEM and tree backref only)
>> +	 *    Records the first key and level of the tree block.
>> +	 *
>> +	 * 2) *Zero* or more btrfs_extent_inline_ref(s)
>> +	 *    Each inline ref has one btrfs_extent_inline_ref shows:
>> +	 *    2.1) The ref type, one of the 4
>> +	 *         TREE_BLOCK_REF	Tree block only
>> +	 *         SHARED_BLOCK_REF	Tree block only
>> +	 *         EXTENT_DATA_REF	Data only
>> +	 *         SHARED_DATA_REF	Data only
>> +	 *    2.2) Ref type specific data
>> +	 *         Either using btrfs_extent_inline_ref::offset, or specific
>> +	 *         data structure.
>> +	 */
>> +	if (item_size < sizeof(*ei)) {
>> +		extent_err(leaf, slot,
>> +			   "invalid item size, have %u expect >= %lu",
>> +			   item_size, sizeof(*ei));
>> +		return -EUCLEAN;
>> +	}
>> +	end = item_size + btrfs_item_ptr_offset(leaf, slot);
>> +
>> +	/* Checks against extent_item */
>> +	ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
>> +	flags = btrfs_extent_flags(leaf, ei);
>> +	total_refs = btrfs_extent_refs(leaf, ei);
>> +	generation = btrfs_extent_generation(leaf, ei);
>> +	if (generation > btrfs_super_generation(fs_info->super_copy) + 1) {
>> +		extent_err(leaf, slot,
>> +			"invalid generation, have %llu expect <= %llu",
>
> nit: I find the '<= [number]' somewhat confusing, wouldn't it be better
> if it's spelled our e.g 'expecting less than or equal than [number]'.
> Might be just me.

I normally prefer the "[start, end]" notion, but sometimes even myself
can't always keep the format the same.

Furthermore, I can't find a minimal value to use [start, end] notion.
Maybe (0, end] would be more suitable here?

>
>> +			   generation,
>> +			   btrfs_super_generation(fs_info->super_copy) + 1);
>> +		return -EUCLEAN;
>> +	}
>> +	if (!is_power_of_2(flags & (BTRFS_EXTENT_FLAG_DATA |
>> +				    BTRFS_EXTENT_FLAG_TREE_BLOCK))) {
>> +		extent_err(leaf, slot,
>> +		"invalid extent flag, have 0x%llx expect 1 bit set in 0x%llx",
>> +			flags, BTRFS_EXTENT_FLAG_DATA |
>> +			BTRFS_EXTENT_FLAG_TREE_BLOCK);
>> +		return -EUCLEAN;
>> +	}
>> +	is_tree_block = !!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK);
>> +	if (is_tree_block && key->type == BTRFS_EXTENT_ITEM_KEY &&
>> +	    key->offset != fs_info->nodesize) {
>> +		extent_err(leaf, slot,
>> +			   "invalid extent length, have %llu expect %u",
>> +			   key->offset, fs_info->nodesize);
>> +		return -EUCLEAN;
>> +	}
>> +	if (!is_tree_block) {
>> +		if (key->type != BTRFS_EXTENT_ITEM_KEY) {
>> +			extent_err(leaf, slot,
>> +		"invalid key type, have %u expect %u for data backref",
>> +				   key->type, BTRFS_EXTENT_ITEM_KEY);
>> +			return -EUCLEAN;
>> +		}
>> +		if (!IS_ALIGNED(key->offset, fs_info->sectorsize)) {
>> +			extent_err(leaf, slot,
>> +			"invalid extent length, have %llu expect aliged to %u",
>> +				   key->offset, fs_info->sectorsize);
>> +			return -EUCLEAN;
>> +		}
>> +	}
>
> unify the two is_tree_block/!is_tree_block either in:
>
> if (is_tree_block) {
> 	if (keypt->type = EXTENT_ITEM_KEY && offset != nodesize {
> 		foo;
> 	}
> } else {
> 	bar;
> }
>

Right, that's better.

> or
>
> if (is_tree_block && key->type == BTRFS_EXTENT_ITEM_KEY ..) {
>
> } else if (!is_tree_block) {
> bar
> }
>
>> +	ptr = (u64)(struct btrfs_extent_item *)(ei + 1);
>> +
>> +	/* Check the special case of btrfs_tree_block_info */
>> +	if (is_tree_block && key->type != BTRFS_METADATA_ITEM_KEY) {
>> +		struct btrfs_tree_block_info *info;
>> +
>> +		info = (struct btrfs_tree_block_info *)ptr;
>> +		if (btrfs_tree_block_level(leaf, info) >= BTRFS_MAX_LEVEL) {
>> +			extent_err(leaf, slot,
>> +			"invalid tree block info level, have %u expect [0, %u)",
>
> nit: Strictly speaking using [0, 7) is wrong, because ')' already
> implies an open interval. Since we have 8 levels 0/7 inclusive this
> means the correct way to print it would be [0, 7] or [0, 8).

It's not that rare I misuses such notion. [0, 7] would be the case.

>
>
>> +				   btrfs_tree_block_level(leaf, info),
>> +				   BTRFS_MAX_LEVEL - 1);
>> +			return -EUCLEAN;
>> +		}
>> +		ptr = (u64)(struct btrfs_tree_block_info *)(info + 1);
>> +	}
>> +
>> +	/* Check inline refs */
>> +	while (ptr < end) {
>> +		struct btrfs_extent_inline_ref *iref;
>> +		struct btrfs_extent_data_ref *dref;
>> +		struct btrfs_shared_data_ref *sref;
>> +		u64 dref_offset;
>> +		u64 inline_offset;
>> +		u8 inline_type;
>> +
>> +		if (ptr + sizeof(*iref) > end) {
>> +			extent_err(leaf, slot,
>> +	"invalid item size, size too small, ptr %llu end %llu",
>> +				   ptr, end);
>> +			goto err;
>> +		}
>> +		iref = (struct btrfs_extent_inline_ref *)ptr;
>> +		inline_type = btrfs_extent_inline_ref_type(leaf, iref);
>> +		inline_offset = btrfs_extent_inline_ref_offset(leaf, iref);
>> +		if (ptr + btrfs_extent_inline_ref_size(inline_type) > end) {
>> +			extent_err(leaf, slot,
>> +	"invalid item size, size too small, ptr %llu end %llu",
>
> Make that text explicit:
>
> "inline ref item overflows extent item" or some such.

OK, I'll use this expression.

Thanks,
Qu

[...]
>> +
>> +	/* Finally, check the inline refs against total refs */
>> +	if (total_refs < inline_refs) {
>
> nit: if (inline_refs > total_refs) {} looks saner to me.
>
>
>
>> +		extent_err(leaf, slot,
>> +			"invalid extent refs, have %llu expect >= %llu",
>> +			   total_refs, inline_refs);
>> +		goto err;
>> +	}
>> +	return 0;
>> +err:
>> +	return -EUCLEAN;
>> +}
>> +
>>  /*
>>   * Common point to switch the item-specific validation.
>>   */
>> @@ -937,6 +1182,10 @@ static int check_leaf_item(struct extent_buffer *leaf,
>>  	case BTRFS_ROOT_ITEM_KEY:
>>  		ret = check_root_item(leaf, key, slot);
>>  		break;
>> +	case BTRFS_EXTENT_ITEM_KEY:
>> +	case BTRFS_METADATA_ITEM_KEY:
>> +		ret = check_extent_item(leaf, key, slot);
>> +		break;
>>  	}
>>  	return ret;
>>  }
>>

  reply	other threads:[~2019-07-29 13:53 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-29  7:43 [PATCH 0/3] btrfs: tree-checker: Add extent items check Qu Wenruo
2019-07-29  7:43 ` [PATCH 1/3] btrfs: tree-checker: Add EXTENT_ITEM and METADATA_ITEM check Qu Wenruo
2019-07-29 13:42   ` Nikolay Borisov
2019-07-29 13:53     ` Qu Wenruo [this message]
2019-07-29  7:43 ` [PATCH 2/3] btrfs: tree-checker: Add simple keyed refs check Qu Wenruo
2019-07-29  7:43 ` [PATCH 3/3] btrfs: tree-checker: Add EXTENT_DATA_REF check 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=66256780-4fa9-9627-151e-62e834a6cc39@gmx.com \
    --to=quwenruo.btrfs@gmx.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=nborisov@suse.com \
    --cc=wqu@suse.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 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).