Btrfs: Combine per-page recover in dev-replace and scrub

The code are similar, combine them to make code clean and easy to maintenance.
Some lost condition are also completed with benefit of this combination.

Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com>
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
Zhao Lei 2015-01-20 15:11:41 +08:00 committed by Chris Mason
parent 8d6738c1bd
commit b968fed1c3
1 changed files with 48 additions and 72 deletions

View File

@ -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;
/* 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++) {
struct scrub_block *sblock_other = sblocks_for_recheck +
if (!sblocks_for_recheck[mirror_index].
pagev[page_num]->io_error) {
sblock_other = sblocks_for_recheck +
mirror_index;
struct scrub_page *page_other = sblock_other->pagev[
page_num];
break;
}
}
if (!sblock_other)
success = 0;
}
if (!page_other->io_error) {
ret = scrub_repair_page_from_good_copy(
sblock_bad, sblock_other, page_num, 0);
if (0 == ret) {
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;
break; /* succeeded for this page */
}
}
}
if (page_bad->io_error) {
/* did not find a mirror to copy the page from */
else
success = 0;
}
}
if (success) {
if (success && !sctx->is_dev_replace) {
if (is_metadata || have_csum) {
/*
* need to verify the checksum now that all