mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	btrfs: scrub: introduce a helper to verify one metadata block
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 from other structures. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									b979547513
								
							
						
					
					
						commit
						a3ddbaebc7
					
				
					 2 changed files with 107 additions and 0 deletions
				
			
		
							
								
								
									
										106
									
								
								fs/btrfs/scrub.c
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								fs/btrfs/scrub.c
									
									
									
									
									
								
							|  | @ -2159,6 +2159,112 @@ static int scrub_checksum_data(struct scrub_block *sblock) | ||||||
| 	return sblock->checksum_error; | 	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 u32 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 generation, has %llu want %llu", | ||||||
|  | 			      logical, stripe->mirror_num, | ||||||
|  | 			      btrfs_stack_header_generation(header), | ||||||
|  | 			      stripe->sectors[sector_nr].generation); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	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) | static int scrub_checksum_tree_block(struct scrub_block *sblock) | ||||||
| { | { | ||||||
| 	struct scrub_ctx *sctx = sblock->sctx; | 	struct scrub_ctx *sctx = sblock->sctx; | ||||||
|  |  | ||||||
|  | @ -24,5 +24,6 @@ int scrub_find_fill_first_stripe(struct btrfs_block_group *bg, | ||||||
| 				 struct btrfs_device *dev, u64 physical, | 				 struct btrfs_device *dev, u64 physical, | ||||||
| 				 int mirror_num, u64 logical_start, | 				 int mirror_num, u64 logical_start, | ||||||
| 				 u32 logical_len, struct scrub_stripe *stripe); | 				 u32 logical_len, struct scrub_stripe *stripe); | ||||||
|  | void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Qu Wenruo
						Qu Wenruo