summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2018-07-11 01:41:21 -0400
committerDavid Sterba <dsterba@suse.com>2018-07-17 07:56:30 -0400
commit665d4953cde6d9e75c62a07ec8f4f8fd7d396ade (patch)
treeb0525c76b5f9497b9d75a7663040eec2410952b3 /fs
parent97b191702b05a7cb9fa6d846adba68419cbbc7a6 (diff)
btrfs: scrub: Don't use inode page cache in scrub_handle_errored_block()
In commit ac0b4145d662 ("btrfs: scrub: Don't use inode pages for device replace") we removed the branch of copy_nocow_pages() to avoid corruption for compressed nodatasum extents. However above commit only solves the problem in scrub_extent(), if during scrub_pages() we failed to read some pages, sctx->no_io_error_seen will be non-zero and we go to fixup function scrub_handle_errored_block(). In scrub_handle_errored_block(), for sctx without csum (no matter if we're doing replace or scrub) we go to scrub_fixup_nodatasum() routine, which does the similar thing with copy_nocow_pages(), but does it without the extra check in copy_nocow_pages() routine. So for test cases like btrfs/100, where we emulate read errors during replace/scrub, we could corrupt compressed extent data again. This patch will fix it just by avoiding any "optimization" for nodatasum, just falls back to the normal fixup routine by try read from any good copy. This also solves WARN_ON() or dead lock caused by lame backref iteration in scrub_fixup_nodatasum() routine. The deadlock or WARN_ON() won't be triggered before commit ac0b4145d662 ("btrfs: scrub: Don't use inode pages for device replace") since copy_nocow_pages() have better locking and extra check for data extent, and it's already doing the fixup work by try to read data from any good copy, so it won't go scrub_fixup_nodatasum() anyway. This patch disables the faulty code and will be removed completely in a followup patch. Fixes: ac0b4145d662 ("btrfs: scrub: Don't use inode pages for device replace") Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/scrub.c17
1 files changed, 9 insertions, 8 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 572306036477..6702896cdb8f 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1151,11 +1151,6 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
1151 return ret; 1151 return ret;
1152 } 1152 }
1153 1153
1154 if (sctx->is_dev_replace && !is_metadata && !have_csum) {
1155 sblocks_for_recheck = NULL;
1156 goto nodatasum_case;
1157 }
1158
1159 /* 1154 /*
1160 * read all mirrors one after the other. This includes to 1155 * read all mirrors one after the other. This includes to
1161 * re-read the extent or metadata block that failed (that was 1156 * re-read the extent or metadata block that failed (that was
@@ -1268,13 +1263,19 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
1268 goto out; 1263 goto out;
1269 } 1264 }
1270 1265
1271 if (!is_metadata && !have_csum) { 1266 /*
1267 * NOTE: Even for nodatasum case, it's still possible that it's a
1268 * compressed data extent, thus scrub_fixup_nodatasum(), which write
1269 * inode page cache onto disk, could cause serious data corruption.
1270 *
1271 * So here we could only read from disk, and hope our recovery could
1272 * reach disk before the newer write.
1273 */
1274 if (0 && !is_metadata && !have_csum) {
1272 struct scrub_fixup_nodatasum *fixup_nodatasum; 1275 struct scrub_fixup_nodatasum *fixup_nodatasum;
1273 1276
1274 WARN_ON(sctx->is_dev_replace); 1277 WARN_ON(sctx->is_dev_replace);
1275 1278
1276nodatasum_case:
1277
1278 /* 1279 /*
1279 * !is_metadata and !have_csum, this means that the data 1280 * !is_metadata and !have_csum, this means that the data
1280 * might not be COWed, that it might be modified 1281 * might not be COWed, that it might be modified