|
@@ -1107,54 +1107,10 @@ nodatasum_case:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * for dev_replace, pick good pages and write to the target device.
|
|
|
- */
|
|
|
- if (sctx->is_dev_replace) {
|
|
|
- success = 1;
|
|
|
- for (page_num = 0; page_num < sblock_bad->page_count;
|
|
|
- page_num++) {
|
|
|
- struct scrub_block *sblock_other = NULL;
|
|
|
-
|
|
|
- for (mirror_index = 0;
|
|
|
- mirror_index < BTRFS_MAX_MIRRORS &&
|
|
|
- sblocks_for_recheck[mirror_index].page_count > 0;
|
|
|
- mirror_index++) {
|
|
|
- if (!sblocks_for_recheck[mirror_index].
|
|
|
- pagev[page_num]->io_error) {
|
|
|
- sblock_other = sblocks_for_recheck +
|
|
|
- mirror_index;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!sblock_other) {
|
|
|
- /*
|
|
|
- * did not find a mirror to fetch the page
|
|
|
- * from. scrub_write_page_to_dev_replace()
|
|
|
- * handles this case (page->io_error), by
|
|
|
- * filling the block with zeros before
|
|
|
- * submitting the write request
|
|
|
- */
|
|
|
- sblock_other = sblock_bad;
|
|
|
- success = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (scrub_write_page_to_dev_replace(sblock_other,
|
|
|
- page_num) != 0) {
|
|
|
- btrfs_dev_replace_stats_inc(
|
|
|
- &sctx->dev_root->
|
|
|
- fs_info->dev_replace.
|
|
|
- num_write_errors);
|
|
|
- success = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ if (sblock_bad->no_io_error_seen && !sctx->is_dev_replace)
|
|
|
+ goto did_not_correct_error;
|
|
|
|
|
|
/*
|
|
|
- * for regular scrub, repair those pages that are errored.
|
|
|
* In case of I/O errors in the area that is supposed to be
|
|
|
* repaired, continue by picking good copies of those pages.
|
|
|
* Select the good pages from mirrors to rewrite bad pages from
|
|
@@ -1178,44 +1134,64 @@ nodatasum_case:
|
|
|
* mirror, even if other 512 byte sectors in the same PAGE_SIZE
|
|
|
* area are unreadable.
|
|
|
*/
|
|
|
-
|
|
|
- /* can only fix I/O errors from here on */
|
|
|
- if (sblock_bad->no_io_error_seen)
|
|
|
- goto did_not_correct_error;
|
|
|
-
|
|
|
success = 1;
|
|
|
- for (page_num = 0; page_num < sblock_bad->page_count; page_num++) {
|
|
|
+ for (page_num = 0; page_num < sblock_bad->page_count;
|
|
|
+ page_num++) {
|
|
|
struct scrub_page *page_bad = sblock_bad->pagev[page_num];
|
|
|
+ struct scrub_block *sblock_other = NULL;
|
|
|
|
|
|
- if (!page_bad->io_error)
|
|
|
+ /* skip no-io-error page in scrub */
|
|
|
+ if (!page_bad->io_error && !sctx->is_dev_replace)
|
|
|
continue;
|
|
|
|
|
|
- for (mirror_index = 0;
|
|
|
- mirror_index < BTRFS_MAX_MIRRORS &&
|
|
|
- sblocks_for_recheck[mirror_index].page_count > 0;
|
|
|
- mirror_index++) {
|
|
|
- struct scrub_block *sblock_other = sblocks_for_recheck +
|
|
|
- mirror_index;
|
|
|
- struct scrub_page *page_other = sblock_other->pagev[
|
|
|
- page_num];
|
|
|
-
|
|
|
- if (!page_other->io_error) {
|
|
|
- ret = scrub_repair_page_from_good_copy(
|
|
|
- sblock_bad, sblock_other, page_num, 0);
|
|
|
- if (0 == ret) {
|
|
|
- page_bad->io_error = 0;
|
|
|
- break; /* succeeded for this page */
|
|
|
+ /* try to find no-io-error page in mirrors */
|
|
|
+ if (page_bad->io_error) {
|
|
|
+ for (mirror_index = 0;
|
|
|
+ mirror_index < BTRFS_MAX_MIRRORS &&
|
|
|
+ sblocks_for_recheck[mirror_index].page_count > 0;
|
|
|
+ mirror_index++) {
|
|
|
+ if (!sblocks_for_recheck[mirror_index].
|
|
|
+ pagev[page_num]->io_error) {
|
|
|
+ sblock_other = sblocks_for_recheck +
|
|
|
+ mirror_index;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
+ if (!sblock_other)
|
|
|
+ success = 0;
|
|
|
}
|
|
|
|
|
|
- if (page_bad->io_error) {
|
|
|
- /* did not find a mirror to copy the page from */
|
|
|
- success = 0;
|
|
|
+ if (sctx->is_dev_replace) {
|
|
|
+ /*
|
|
|
+ * did not find a mirror to fetch the page
|
|
|
+ * from. scrub_write_page_to_dev_replace()
|
|
|
+ * handles this case (page->io_error), by
|
|
|
+ * filling the block with zeros before
|
|
|
+ * submitting the write request
|
|
|
+ */
|
|
|
+ if (!sblock_other)
|
|
|
+ sblock_other = sblock_bad;
|
|
|
+
|
|
|
+ if (scrub_write_page_to_dev_replace(sblock_other,
|
|
|
+ page_num) != 0) {
|
|
|
+ btrfs_dev_replace_stats_inc(
|
|
|
+ &sctx->dev_root->
|
|
|
+ fs_info->dev_replace.
|
|
|
+ num_write_errors);
|
|
|
+ success = 0;
|
|
|
+ }
|
|
|
+ } else if (sblock_other) {
|
|
|
+ ret = scrub_repair_page_from_good_copy(sblock_bad,
|
|
|
+ sblock_other,
|
|
|
+ page_num, 0);
|
|
|
+ if (0 == ret)
|
|
|
+ page_bad->io_error = 0;
|
|
|
+ else
|
|
|
+ success = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (success) {
|
|
|
+ if (success && !sctx->is_dev_replace) {
|
|
|
if (is_metadata || have_csum) {
|
|
|
/*
|
|
|
* need to verify the checksum now that all
|