Skip to content

Commit

Permalink
Btrfs: Combine per-page recover in dev-replace and scrub
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Miao Xie <[email protected]>
Signed-off-by: Chris Mason <[email protected]>
  • Loading branch information
zhaoleidd authored and masoncl committed Jan 22, 2015
1 parent 8d6738c commit b968fed
Showing 1 changed file with 48 additions and 72 deletions.
120 changes: 48 additions & 72 deletions fs/btrfs/scrub.c
Original file line number Diff line number Diff line change
Expand Up @@ -1107,54 +1107,10 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
}
}

/*
* 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
Expand All @@ -1178,44 +1134,64 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
* 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
Expand Down

0 comments on commit b968fed

Please sign in to comment.