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…
Add table
Reference in a new issue