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:
parent
8d6738c1bd
commit
b968fed1c3
120
fs/btrfs/scrub.c
120
fs/btrfs/scrub.c
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue