diff mbox series

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

Message ID eb752c34ca23d5d55ce7df9b43cdcb5f52b97490.1680225140.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 31, 2023, 1:20 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>
Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/scrub.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/scrub.h |   1 +
 2 files changed, 117 insertions(+)

Comments

David Sterba April 5, 2023, 3:28 p.m. UTC | #1
On Fri, Mar 31, 2023 at 09:20:09AM +0800, Qu Wenruo wrote:
> +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 *header;
> +
> +	/*
> +	 * 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.
> +	 */
> +	header = (struct btrfs_header *)(page_address(first_page) + first_off);
> +	memcpy(on_disk_csum, header->csum, fs_info->csum_size);
> +
> +	if (logical != btrfs_stack_header_bytenr(header)) {
> +		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(header), logical);
> +		return;
> +	}
> +	if (memcmp(header->fsid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE) != 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,
> +			      header->fsid, fs_info->fs_devices->fsid);
> +		return;
> +	}
> +	if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
> +		   BTRFS_UUID_SIZE) != 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 chunk tree uuid, has %pU want %pU",
> +			      logical, stripe->mirror_num,
> +			      header->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 (int 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) != 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 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(header)) {
> +		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(header),
> +			      stripe->sectors[sector_nr].generation);

Is return; missing here?

> +	}
> +	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);
> +}
Qu Wenruo April 5, 2023, 11:44 p.m. UTC | #2
On 2023/4/5 23:28, David Sterba wrote:
> On Fri, Mar 31, 2023 at 09:20:09AM +0800, Qu Wenruo wrote:
>> +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 *header;
>> +
>> +	/*
>> +	 * 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.
>> +	 */
>> +	header = (struct btrfs_header *)(page_address(first_page) + first_off);
>> +	memcpy(on_disk_csum, header->csum, fs_info->csum_size);
>> +
>> +	if (logical != btrfs_stack_header_bytenr(header)) {
>> +		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(header), logical);
>> +		return;
>> +	}
>> +	if (memcmp(header->fsid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE) != 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,
>> +			      header->fsid, fs_info->fs_devices->fsid);
>> +		return;
>> +	}
>> +	if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
>> +		   BTRFS_UUID_SIZE) != 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 chunk tree uuid, has %pU want %pU",
>> +			      logical, stripe->mirror_num,
>> +			      header->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 (int 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) != 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 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(header)) {
>> +		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(header),
>> +			      stripe->sectors[sector_nr].generation);
> 
> Is return; missing here?

Oh, right we should return or we clear the error bitmap.

Thanks,
Qu
> 
>> +	}
>> +	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 00f43e3a2471..33ff0dc6a785 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -2159,6 +2159,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 *header;
+
+	/*
+	 * 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.
+	 */
+	header = (struct btrfs_header *)(page_address(first_page) + first_off);
+	memcpy(on_disk_csum, header->csum, fs_info->csum_size);
+
+	if (logical != btrfs_stack_header_bytenr(header)) {
+		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(header), logical);
+		return;
+	}
+	if (memcmp(header->fsid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE) != 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,
+			      header->fsid, fs_info->fs_devices->fsid);
+		return;
+	}
+	if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
+		   BTRFS_UUID_SIZE) != 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 chunk tree uuid, has %pU want %pU",
+			      logical, stripe->mirror_num,
+			      header->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 (int 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) != 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 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(header)) {
+		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(header),
+			      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