From 9be798867718770263e663de3be7361e8422d96c Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 27 Feb 2018 17:12:56 +0800 Subject: btrfs-progs: check: Check data csum for all copies Original --check-data-csum option will skip the extra copy if the first copy matches csum. Since offline scrub (with recoverability report) is still out-of-tree, at least enhance --check-data-csum option to handle multiple copies. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- check/main.c | 70 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/check/main.c b/check/main.c index c4a1801f..03af0d43 100644 --- a/check/main.c +++ b/check/main.c @@ -5406,42 +5406,42 @@ static int check_extent_csums(struct btrfs_root *root, u64 bytenr, if (!data) return -ENOMEM; + num_copies = btrfs_num_copies(root->fs_info, bytenr, num_bytes); while (offset < num_bytes) { - mirror = 0; -again: - read_len = num_bytes - offset; - /* read as much space once a time */ - ret = read_extent_data(fs_info, data + offset, - bytenr + offset, &read_len, mirror); - if (ret) - goto out; - data_checked = 0; - /* verify every 4k data's checksum */ - while (data_checked < read_len) { - csum = ~(u32)0; - tmp = offset + data_checked; - - csum = btrfs_csum_data((char *)data + tmp, - csum, fs_info->sectorsize); - btrfs_csum_final(csum, (u8 *)&csum); - - csum_offset = leaf_offset + - tmp / fs_info->sectorsize * csum_size; - read_extent_buffer(eb, (char *)&csum_expected, - csum_offset, csum_size); - /* try another mirror */ - if (csum != csum_expected) { - fprintf(stderr, "mirror %d bytenr %llu csum %u expected csum %u\n", + /* + * Mirror 0 means 'read from any valid copy', so it's skipped. + * The indexes 1-N represent the n-th copy for levels with + * redundancy. + */ + for (mirror = 1; mirror <= num_copies; mirror++) { + read_len = num_bytes - offset; + /* read as much space once a time */ + ret = read_extent_data(fs_info, data + offset, + bytenr + offset, &read_len, mirror); + if (ret) + goto out; + + data_checked = 0; + /* verify every 4k data's checksum */ + while (data_checked < read_len) { + csum = ~(u32)0; + tmp = offset + data_checked; + + csum = btrfs_csum_data((char *)data + tmp, + csum, fs_info->sectorsize); + btrfs_csum_final(csum, (u8 *)&csum); + + csum_offset = leaf_offset + + tmp / fs_info->sectorsize * csum_size; + read_extent_buffer(eb, (char *)&csum_expected, + csum_offset, csum_size); + if (csum != csum_expected) + fprintf(stderr, + "mirror %d bytenr %llu csum %u expected csum %u\n", mirror, bytenr + tmp, csum, csum_expected); - num_copies = btrfs_num_copies(root->fs_info, - bytenr, num_bytes); - if (mirror < num_copies - 1) { - mirror += 1; - goto again; - } + data_checked += fs_info->sectorsize; } - data_checked += fs_info->sectorsize; } offset += read_len; } @@ -5660,7 +5660,11 @@ static int check_csums(struct btrfs_root *root) leaf_offset = btrfs_item_ptr_offset(leaf, path.slots[0]); ret = check_extent_csums(root, key.offset, data_len, leaf_offset, leaf); - if (ret) + /* + * Only break for fatal errors, if mismatch is found, continue + * checking until all extents are checked. + */ + if (ret < 0) break; skip_csum_check: if (!num_bytes) { -- cgit v1.2.3