On Tue, May 29, 2018 at 03:45:27PM +0800, Qu Wenruo wrote: >As the lzo corruption reported by James Harvey, for data extents without >checksum, neither btrfs check nor kernel scrub could detect anything >wrong. > >However if our profile supports duplication, we still have a chance to >detect such corruption, as in that case the mirrors will mismatch with >each other. > >So enhance --check-data-csum option to do such check, and this could >help us to detect such corruption in an autonomous test case. > >Signed-off-by: Qu Wenruo <w...@suse.com>
Overall looks good to me. Reviewed-by: Lu Fengqi <lufq.f...@cn.fujitsu.com> But a small nitpick inlined below: >--- > Documentation/btrfs-check.asciidoc | 2 + > check/main.c | 161 ++++++++++++++++++++++++++++- > 2 files changed, 162 insertions(+), 1 deletion(-) > >diff --git a/Documentation/btrfs-check.asciidoc >b/Documentation/btrfs-check.asciidoc >index b963eae5cdce..34173acbc523 100644 >--- a/Documentation/btrfs-check.asciidoc >+++ b/Documentation/btrfs-check.asciidoc >@@ -51,6 +51,8 @@ verify checksums of data blocks > + > This expects that the filesystem is otherwise OK, and is basically and offline > 'scrub' but does not repair data from spare copies. >+Also, for data extent without checksum (NODATASUM), it will compare data >+between mirrors to detect any possible mismatch. > > --chunk-root <bytenr>:: > use the given offset 'bytenr' for the chunk tree root >diff --git a/check/main.c b/check/main.c >index 68da994f7ae0..2ea965fc2fed 100644 >--- a/check/main.c >+++ b/check/main.c >@@ -5602,6 +5602,148 @@ out: > return ret; > } > >+/* >+ * Return 0 if both mirrors match >+ * Return >0 if mirrors mismatch >+ * Return <0 for fatal error >+ */ >+static int compare_extent_mirrors(struct btrfs_fs_info *fs_info, u64 bytenr, >+ u64 len) >+{ >+ u64 cur; >+ const int buf_size = SZ_128K; >+ char buf1[buf_size]; >+ char buf2[buf_size]; >+ int ret; >+ >+ if (btrfs_num_copies(fs_info, bytenr, len) != 2) >+ return -EINVAL; >+ >+ for (cur = bytenr; cur < bytenr + len; cur += buf_size) { >+ u64 cur_len = min_t(u64, buf_size, bytenr + len - cur); >+ >+ ret = read_data_from_disk(fs_info, buf1, cur, cur_len, 1); >+ if (ret < 0) >+ return ret; >+ ret = read_data_from_disk(fs_info, buf2, cur, cur_len, 2); >+ if (ret < 0) >+ return ret; >+ if (memcmp(buf1, buf2, cur_len)) >+ return 1; >+ } >+ return 0; >+} >+ >+static int check_bg_mirrors_for_nodatasum(struct btrfs_fs_info *fs_info, >+ struct btrfs_block_group_cache *bg) >+{ >+ struct btrfs_root *extent_root = fs_info->extent_root; >+ struct btrfs_key key; >+ struct btrfs_path path; >+ int errors = 0; >+ int ret; >+ >+ key.objectid = bg->key.objectid; >+ key.type = 0; >+ key.offset = 0; >+ btrfs_init_path(&path); >+ >+ ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0); >+ if (ret < 0) >+ return ret; >+ if (ret == 0) { >+ /* Such key should not exist, something goes wrong */ >+ ret = -EUCLEAN; >+ goto error; >+ } >+ >+ while (1) { >+ u64 csum_found; >+ >+ btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]); >+ if (key.type != BTRFS_EXTENT_ITEM_KEY) >+ goto next; >+ ret = count_csum_range(fs_info, key.objectid, key.offset, >+ &csum_found); >+ if (ret < 0) >+ goto error; >+ /* >+ * Here we don't care if csum is covering the whole extent, >+ * as if it's true it's half csumed, file extent check will >+ * report, we only care if it's without csum at all >+ */ >+ if (csum_found) >+ goto next; >+ ret = compare_extent_mirrors(fs_info, key.objectid, key.offset); >+ if (ret < 0) { >+ error( >+ "failed to compare data extent mirrors for bytenr %llu len %llu: %s", >+ key.objectid, key.offset, strerror(-ret)); >+ goto error; >+ } >+ if (ret > 0) { >+ error( >+ "found data mismatch for NODATASUM extent, at bytenr %llu len %llu", >+ key.objectid, key.offset); >+ errors++; >+ } >+next: >+ ret = btrfs_next_extent_item(extent_root, &path, >+ bg->key.objectid + bg->key.offset - 1); >+ if (ret < 0) >+ goto error; >+ if (ret > 0) >+ break; >+ } >+ btrfs_release_path(&path); >+ return errors; >+ >+error: >+ btrfs_release_path(&path); >+ return ret; >+} >+ >+/* >+ * Check for any data extent without csum, and then compare its data with >+ * any existing mirror to detect any possible corruption. >+ * >+ * Return 0 for all good. >+ * Return <0 for fatal error. (Like failed to read tree blocks) >+ * Return >0 for how many mismatched extents found. >+ */ >+static int check_mirrors_for_nodatasum(struct btrfs_fs_info *fs_info) >+{ >+ struct btrfs_block_group_cache *bg; >+ int ret; >+ int errors = 0; >+ >+ bg = btrfs_lookup_first_block_group(fs_info, 0); >+ if (!bg) >+ return -EUCLEAN; >+ >+ while (bg) { >+ /* Here we only care about data block groups */ >+ if (!(bg->flags & BTRFS_BLOCK_GROUP_DATA)) >+ goto next; >+ /* >+ * And it must be mirrored profile >+ * NOTE: For RAID5/6 it's not yet supported yet. >+ */ >+ if (!((BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP | >+ BTRFS_BLOCK_GROUP_RAID10) & bg->flags)) >+ goto next; >+ ret = check_bg_mirrors_for_nodatasum(fs_info, bg); >+ /* Fatal error, exist right now */ >+ if (ret < 0) >+ return ret; >+ errors += ret; >+next: >+ bg = btrfs_lookup_first_block_group(fs_info, >+ bg->key.objectid + bg->key.offset); >+ } >+ return errors; >+} >+ > static int check_csums(struct btrfs_root *root) > { > struct btrfs_path path; >@@ -5697,8 +5839,25 @@ skip_csum_check: > num_bytes += data_len; > path.slots[0]++; > } >- > btrfs_release_path(&path); >+ >+ /* >+ * Do extra check on mirror consistence for NODATASUM case if >+ * --check-datasum is specified. [nit] s/check-datasum/check-data-csum -- Thanks, Lu >+ * For NODATASUM case, we can still check if both copies match. >+ */ >+ if (verify_csum) { >+ ret = check_mirrors_for_nodatasum(root->fs_info); >+ if (ret < 0) { >+ error( >+ "failed to check consistence for data without checksum: %s", >+ strerror(-ret)); >+ errors++; >+ } >+ if (ret > 0) >+ errors += ret; >+ } >+ > return errors; > } > >-- >2.17.0 > >-- >To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in >the body of a message to majord...@vger.kernel.org >More majordomo info at http://vger.kernel.org/majordomo-info.html > > -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html