diff mbox series

[v3,06/12] btrfs: scrub: introduce a helper to verify one metadata

Message ID 247d7a3f94cc940a8dceb03bc6357f9577c7d394.1679278088.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: scrub: use a more reader friendly code to implement scrub_simple_mirror() | expand

Commit Message

Qu Wenruo March 20, 2023, 2:12 a.m. UTC
The new helper, scrub_verify_one_metadata(), is almost the same as
scrub_checksum_tree_block().

The difference is in how we grab the pages.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/scrub.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/scrub.h |   1 +
 2 files changed, 117 insertions(+)

Comments

David Sterba March 21, 2023, 12:31 a.m. UTC | #1
On Mon, Mar 20, 2023 at 10:12:52AM +0800, Qu Wenruo wrote:
> --- a/fs/btrfs/scrub.c
> +++ b/fs/btrfs/scrub.c
> @@ -2157,6 +2157,122 @@ static int scrub_checksum_data(struct scrub_block *sblock)
>  	return sblock->checksum_error;
>  }
>  
> +static struct page *scrub_stripe_get_page(struct scrub_stripe *stripe,
> +					  int sector_nr)
> +{
> +	struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
> +	int page_index = sector_nr << fs_info->sectorsize_bits >> PAGE_SHIFT;

This needs ( ) to make it clear what you mean and actually shifts are
safer to be done on unsigned types (for sector_nr).

> +
> +	return stripe->pages[page_index];
> +}
> +
> +static unsigned int scrub_stripe_get_page_offset(struct scrub_stripe *stripe,
> +						 int sector_nr)
> +{
> +	struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
> +
> +	return offset_in_page(sector_nr << fs_info->sectorsize_bits);
> +}
> +
> +void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr)
> +{
> +	struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
> +	const unsigned int sectors_per_tree = fs_info->nodesize >>
> +					      fs_info->sectorsize_bits;
> +	const u64 logical = stripe->logical + (sector_nr << fs_info->sectorsize_bits);
> +	const struct page *first_page = scrub_stripe_get_page(stripe, sector_nr);
> +	const unsigned int first_off = scrub_stripe_get_page_offset(stripe, sector_nr);
> +	SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
> +	u8 on_disk_csum[BTRFS_CSUM_SIZE];
> +	u8 calculated_csum[BTRFS_CSUM_SIZE];
> +	struct btrfs_header *h;

Please don't use single letter variables for anything else than integer
array indexes, like i. Here it it's hdr or header. Though it's probably
copied from the old code, new code should improve the style.

> +	int i;
> +
> +	/*
> +	 * Here we don't have a good way to attach the pages (and subpages)
> +	 * to a dummy extent buffer, thus we have to directly grab the members
> +	 * from pages.
> +	 */
> +	h = (struct btrfs_header *)(page_address(first_page) + first_off);
> +	memcpy(on_disk_csum, h->csum, fs_info->csum_size);
> +
> +	if (logical != btrfs_stack_header_bytenr(h)) {
> +		bitmap_set(&stripe->csum_error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		bitmap_set(&stripe->error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		btrfs_warn_rl(fs_info,
> +		"tree block %llu mirror %u has bad bytenr, has %llu want %llu",
> +			      logical, stripe->mirror_num,
> +			      btrfs_stack_header_bytenr(h), logical);
> +		return;
> +	}
> +	if (memcmp(h->fsid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE)) {

For memcmp please use explicit == 0 or != 0

> +		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		bitmap_set(&stripe->error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		btrfs_warn_rl(fs_info,
> +		"tree block %llu mirror %u has bad fsid, has %pU want %pU",
> +			      logical, stripe->mirror_num,
> +			      h->fsid, fs_info->fs_devices->fsid);
> +		return;
> +	}
> +	if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
> +		   BTRFS_UUID_SIZE)) {

Same

> +		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		bitmap_set(&stripe->error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		btrfs_warn_rl(fs_info,
> +		"tree block %llu mirror %u has bad chunk tree uuid, has %pU want %pU",
> +			      logical, stripe->mirror_num,
> +			      h->chunk_tree_uuid, fs_info->chunk_tree_uuid);
> +		return;
> +	}
> +
> +	/* Now check tree block csum. */
> +	shash->tfm = fs_info->csum_shash;
> +	crypto_shash_init(shash);
> +	crypto_shash_update(shash, page_address(first_page) + first_off +
> +			    BTRFS_CSUM_SIZE, fs_info->sectorsize - BTRFS_CSUM_SIZE);
> +
> +	for (i = sector_nr + 1; i < sector_nr + sectors_per_tree; i++) {
> +		struct page *page = scrub_stripe_get_page(stripe, i);
> +		unsigned int page_off = scrub_stripe_get_page_offset(stripe, i);
> +
> +		crypto_shash_update(shash, page_address(page) + page_off,
> +				    fs_info->sectorsize);
> +	}
> +	crypto_shash_final(shash, calculated_csum);
> +	if (memcmp(calculated_csum, on_disk_csum, fs_info->csum_size)) {

Same

> +		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		bitmap_set(&stripe->error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		btrfs_warn_rl(fs_info,
> +		"tree block %llu mirror %u has bad csum, has " CSUM_FMT " want " CSUM_FMT,
> +			      logical, stripe->mirror_num,
> +			      CSUM_FMT_VALUE(fs_info->csum_size, on_disk_csum),
> +			      CSUM_FMT_VALUE(fs_info->csum_size, calculated_csum));
> +		return;
> +	}
> +	if (stripe->sectors[sector_nr].generation != btrfs_stack_header_generation(h)) {
> +		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		bitmap_set(&stripe->error_bitmap, sector_nr,
> +			   sectors_per_tree);
> +		btrfs_warn_rl(fs_info,
> +		"tree block %llu mirror %u has bad geneartion, has %llu want %llu",
> +			      logical, stripe->mirror_num,
> +			      btrfs_stack_header_generation(h),
> +			      stripe->sectors[sector_nr].generation);
> +	}
> +	bitmap_clear(&stripe->error_bitmap, sector_nr, sectors_per_tree);
> +	bitmap_clear(&stripe->csum_error_bitmap, sector_nr, sectors_per_tree);
> +	bitmap_clear(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
> +}
diff mbox series

Patch

diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index d44007cccad3..f3445c7f5dc1 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -2157,6 +2157,122 @@  static int scrub_checksum_data(struct scrub_block *sblock)
 	return sblock->checksum_error;
 }
 
+static struct page *scrub_stripe_get_page(struct scrub_stripe *stripe,
+					  int sector_nr)
+{
+	struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
+	int page_index = sector_nr << fs_info->sectorsize_bits >> PAGE_SHIFT;
+
+	return stripe->pages[page_index];
+}
+
+static unsigned int scrub_stripe_get_page_offset(struct scrub_stripe *stripe,
+						 int sector_nr)
+{
+	struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
+
+	return offset_in_page(sector_nr << fs_info->sectorsize_bits);
+}
+
+void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr)
+{
+	struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
+	const unsigned int sectors_per_tree = fs_info->nodesize >>
+					      fs_info->sectorsize_bits;
+	const u64 logical = stripe->logical + (sector_nr << fs_info->sectorsize_bits);
+	const struct page *first_page = scrub_stripe_get_page(stripe, sector_nr);
+	const unsigned int first_off = scrub_stripe_get_page_offset(stripe, sector_nr);
+	SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
+	u8 on_disk_csum[BTRFS_CSUM_SIZE];
+	u8 calculated_csum[BTRFS_CSUM_SIZE];
+	struct btrfs_header *h;
+	int i;
+
+	/*
+	 * Here we don't have a good way to attach the pages (and subpages)
+	 * to a dummy extent buffer, thus we have to directly grab the members
+	 * from pages.
+	 */
+	h = (struct btrfs_header *)(page_address(first_page) + first_off);
+	memcpy(on_disk_csum, h->csum, fs_info->csum_size);
+
+	if (logical != btrfs_stack_header_bytenr(h)) {
+		bitmap_set(&stripe->csum_error_bitmap, sector_nr,
+			   sectors_per_tree);
+		bitmap_set(&stripe->error_bitmap, sector_nr,
+			   sectors_per_tree);
+		btrfs_warn_rl(fs_info,
+		"tree block %llu mirror %u has bad bytenr, has %llu want %llu",
+			      logical, stripe->mirror_num,
+			      btrfs_stack_header_bytenr(h), logical);
+		return;
+	}
+	if (memcmp(h->fsid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE)) {
+		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
+			   sectors_per_tree);
+		bitmap_set(&stripe->error_bitmap, sector_nr,
+			   sectors_per_tree);
+		btrfs_warn_rl(fs_info,
+		"tree block %llu mirror %u has bad fsid, has %pU want %pU",
+			      logical, stripe->mirror_num,
+			      h->fsid, fs_info->fs_devices->fsid);
+		return;
+	}
+	if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
+		   BTRFS_UUID_SIZE)) {
+		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
+			   sectors_per_tree);
+		bitmap_set(&stripe->error_bitmap, sector_nr,
+			   sectors_per_tree);
+		btrfs_warn_rl(fs_info,
+		"tree block %llu mirror %u has bad chunk tree uuid, has %pU want %pU",
+			      logical, stripe->mirror_num,
+			      h->chunk_tree_uuid, fs_info->chunk_tree_uuid);
+		return;
+	}
+
+	/* Now check tree block csum. */
+	shash->tfm = fs_info->csum_shash;
+	crypto_shash_init(shash);
+	crypto_shash_update(shash, page_address(first_page) + first_off +
+			    BTRFS_CSUM_SIZE, fs_info->sectorsize - BTRFS_CSUM_SIZE);
+
+	for (i = sector_nr + 1; i < sector_nr + sectors_per_tree; i++) {
+		struct page *page = scrub_stripe_get_page(stripe, i);
+		unsigned int page_off = scrub_stripe_get_page_offset(stripe, i);
+
+		crypto_shash_update(shash, page_address(page) + page_off,
+				    fs_info->sectorsize);
+	}
+	crypto_shash_final(shash, calculated_csum);
+	if (memcmp(calculated_csum, on_disk_csum, fs_info->csum_size)) {
+		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
+			   sectors_per_tree);
+		bitmap_set(&stripe->error_bitmap, sector_nr,
+			   sectors_per_tree);
+		btrfs_warn_rl(fs_info,
+		"tree block %llu mirror %u has bad csum, has " CSUM_FMT " want " CSUM_FMT,
+			      logical, stripe->mirror_num,
+			      CSUM_FMT_VALUE(fs_info->csum_size, on_disk_csum),
+			      CSUM_FMT_VALUE(fs_info->csum_size, calculated_csum));
+		return;
+	}
+	if (stripe->sectors[sector_nr].generation != btrfs_stack_header_generation(h)) {
+		bitmap_set(&stripe->meta_error_bitmap, sector_nr,
+			   sectors_per_tree);
+		bitmap_set(&stripe->error_bitmap, sector_nr,
+			   sectors_per_tree);
+		btrfs_warn_rl(fs_info,
+		"tree block %llu mirror %u has bad geneartion, has %llu want %llu",
+			      logical, stripe->mirror_num,
+			      btrfs_stack_header_generation(h),
+			      stripe->sectors[sector_nr].generation);
+	}
+	bitmap_clear(&stripe->error_bitmap, sector_nr, sectors_per_tree);
+	bitmap_clear(&stripe->csum_error_bitmap, sector_nr, sectors_per_tree);
+	bitmap_clear(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
+}
+
 static int scrub_checksum_tree_block(struct scrub_block *sblock)
 {
 	struct scrub_ctx *sctx = sblock->sctx;
diff --git a/fs/btrfs/scrub.h b/fs/btrfs/scrub.h
index 27019d86b539..0d8bdc7df89c 100644
--- a/fs/btrfs/scrub.h
+++ b/fs/btrfs/scrub.h
@@ -24,5 +24,6 @@  int scrub_find_fill_first_stripe(struct btrfs_block_group *bg,
 				 struct btrfs_device *dev, u64 physical,
 				 int mirror_num, u64 logical_start,
 				 u32 logical_len, struct scrub_stripe *stripe);
+void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr);
 
 #endif