]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Btrfs: Combine per-page recover in dev-replace and scrub
authorZhao Lei <zhaolei@cn.fujitsu.com>
Tue, 20 Jan 2015 07:11:41 +0000 (15:11 +0800)
committerChris Mason <clm@fb.com>
Thu, 22 Jan 2015 02:06:49 +0000 (18:06 -0800)
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>
fs/btrfs/scrub.c

index c40ffbc9581f781be9872184f0ef19410ce777fa..aac40aefa552ddb60130a6951ebe57c9ba92da36 100644 (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;
 
-               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