Skip to content

Commit a3ddbae

Browse files
adam900710kdave
authored andcommitted
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>
1 parent b979547 commit a3ddbae

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

fs/btrfs/scrub.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,6 +2159,112 @@ static int scrub_checksum_data(struct scrub_block *sblock)
21592159
return sblock->checksum_error;
21602160
}
21612161

2162+
static struct page *scrub_stripe_get_page(struct scrub_stripe *stripe, int sector_nr)
2163+
{
2164+
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
2165+
int page_index = (sector_nr << fs_info->sectorsize_bits) >> PAGE_SHIFT;
2166+
2167+
return stripe->pages[page_index];
2168+
}
2169+
2170+
static unsigned int scrub_stripe_get_page_offset(struct scrub_stripe *stripe,
2171+
int sector_nr)
2172+
{
2173+
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
2174+
2175+
return offset_in_page(sector_nr << fs_info->sectorsize_bits);
2176+
}
2177+
2178+
void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr)
2179+
{
2180+
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
2181+
const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
2182+
const u64 logical = stripe->logical + (sector_nr << fs_info->sectorsize_bits);
2183+
const struct page *first_page = scrub_stripe_get_page(stripe, sector_nr);
2184+
const unsigned int first_off = scrub_stripe_get_page_offset(stripe, sector_nr);
2185+
SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
2186+
u8 on_disk_csum[BTRFS_CSUM_SIZE];
2187+
u8 calculated_csum[BTRFS_CSUM_SIZE];
2188+
struct btrfs_header *header;
2189+
2190+
/*
2191+
* Here we don't have a good way to attach the pages (and subpages)
2192+
* to a dummy extent buffer, thus we have to directly grab the members
2193+
* from pages.
2194+
*/
2195+
header = (struct btrfs_header *)(page_address(first_page) + first_off);
2196+
memcpy(on_disk_csum, header->csum, fs_info->csum_size);
2197+
2198+
if (logical != btrfs_stack_header_bytenr(header)) {
2199+
bitmap_set(&stripe->csum_error_bitmap, sector_nr, sectors_per_tree);
2200+
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
2201+
btrfs_warn_rl(fs_info,
2202+
"tree block %llu mirror %u has bad bytenr, has %llu want %llu",
2203+
logical, stripe->mirror_num,
2204+
btrfs_stack_header_bytenr(header), logical);
2205+
return;
2206+
}
2207+
if (memcmp(header->fsid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE) != 0) {
2208+
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
2209+
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
2210+
btrfs_warn_rl(fs_info,
2211+
"tree block %llu mirror %u has bad fsid, has %pU want %pU",
2212+
logical, stripe->mirror_num,
2213+
header->fsid, fs_info->fs_devices->fsid);
2214+
return;
2215+
}
2216+
if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
2217+
BTRFS_UUID_SIZE) != 0) {
2218+
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
2219+
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
2220+
btrfs_warn_rl(fs_info,
2221+
"tree block %llu mirror %u has bad chunk tree uuid, has %pU want %pU",
2222+
logical, stripe->mirror_num,
2223+
header->chunk_tree_uuid, fs_info->chunk_tree_uuid);
2224+
return;
2225+
}
2226+
2227+
/* Now check tree block csum. */
2228+
shash->tfm = fs_info->csum_shash;
2229+
crypto_shash_init(shash);
2230+
crypto_shash_update(shash, page_address(first_page) + first_off +
2231+
BTRFS_CSUM_SIZE, fs_info->sectorsize - BTRFS_CSUM_SIZE);
2232+
2233+
for (int i = sector_nr + 1; i < sector_nr + sectors_per_tree; i++) {
2234+
struct page *page = scrub_stripe_get_page(stripe, i);
2235+
unsigned int page_off = scrub_stripe_get_page_offset(stripe, i);
2236+
2237+
crypto_shash_update(shash, page_address(page) + page_off,
2238+
fs_info->sectorsize);
2239+
}
2240+
2241+
crypto_shash_final(shash, calculated_csum);
2242+
if (memcmp(calculated_csum, on_disk_csum, fs_info->csum_size) != 0) {
2243+
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
2244+
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
2245+
btrfs_warn_rl(fs_info,
2246+
"tree block %llu mirror %u has bad csum, has " CSUM_FMT " want " CSUM_FMT,
2247+
logical, stripe->mirror_num,
2248+
CSUM_FMT_VALUE(fs_info->csum_size, on_disk_csum),
2249+
CSUM_FMT_VALUE(fs_info->csum_size, calculated_csum));
2250+
return;
2251+
}
2252+
if (stripe->sectors[sector_nr].generation !=
2253+
btrfs_stack_header_generation(header)) {
2254+
bitmap_set(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
2255+
bitmap_set(&stripe->error_bitmap, sector_nr, sectors_per_tree);
2256+
btrfs_warn_rl(fs_info,
2257+
"tree block %llu mirror %u has bad generation, has %llu want %llu",
2258+
logical, stripe->mirror_num,
2259+
btrfs_stack_header_generation(header),
2260+
stripe->sectors[sector_nr].generation);
2261+
return;
2262+
}
2263+
bitmap_clear(&stripe->error_bitmap, sector_nr, sectors_per_tree);
2264+
bitmap_clear(&stripe->csum_error_bitmap, sector_nr, sectors_per_tree);
2265+
bitmap_clear(&stripe->meta_error_bitmap, sector_nr, sectors_per_tree);
2266+
}
2267+
21622268
static int scrub_checksum_tree_block(struct scrub_block *sblock)
21632269
{
21642270
struct scrub_ctx *sctx = sblock->sctx;

fs/btrfs/scrub.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ int scrub_find_fill_first_stripe(struct btrfs_block_group *bg,
2424
struct btrfs_device *dev, u64 physical,
2525
int mirror_num, u64 logical_start,
2626
u32 logical_len, struct scrub_stripe *stripe);
27+
void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr);
2728

2829
#endif

0 commit comments

Comments
 (0)