aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/scrub.c
diff options
context:
space:
mode:
authorZhao Lei <zhaolei@cn.fujitsu.com>2015-01-20 02:11:41 -0500
committerChris Mason <clm@fb.com>2015-01-21 21:06:49 -0500
commitb968fed1c3810a0a0d575cab8a72431fbc807615 (patch)
treefd5aa5d589e91e11de1f86dfef6157ff59988fc1 /fs/btrfs/scrub.c
parent8d6738c1bd74a27ff6a5043c5211c7bff7745420 (diff)
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>
Diffstat (limited to 'fs/btrfs/scrub.c')
-rw-r--r--fs/btrfs/scrub.c120
1 files changed, 48 insertions, 72 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index c40ffbc9581f..aac40aefa552 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1107,54 +1107,10 @@ nodatasum_case:
1107 } 1107 }
1108 } 1108 }
1109 1109
1110 /* 1110 if (sblock_bad->no_io_error_seen && !sctx->is_dev_replace)
1111 * for dev_replace, pick good pages and write to the target device. 1111 goto did_not_correct_error;
1112 */
1113 if (sctx->is_dev_replace) {
1114 success = 1;
1115 for (page_num = 0; page_num < sblock_bad->page_count;
1116 page_num++) {
1117 struct scrub_block *sblock_other = NULL;
1118
1119 for (mirror_index = 0;
1120 mirror_index < BTRFS_MAX_MIRRORS &&
1121 sblocks_for_recheck[mirror_index].page_count > 0;
1122 mirror_index++) {
1123 if (!sblocks_for_recheck[mirror_index].
1124 pagev[page_num]->io_error) {
1125 sblock_other = sblocks_for_recheck +
1126 mirror_index;
1127 break;
1128 }
1129 }
1130
1131 if (!sblock_other) {
1132 /*
1133 * did not find a mirror to fetch the page
1134 * from. scrub_write_page_to_dev_replace()
1135 * handles this case (page->io_error), by
1136 * filling the block with zeros before
1137 * submitting the write request
1138 */
1139 sblock_other = sblock_bad;
1140 success = 0;
1141 }
1142
1143 if (scrub_write_page_to_dev_replace(sblock_other,
1144 page_num) != 0) {
1145 btrfs_dev_replace_stats_inc(
1146 &sctx->dev_root->
1147 fs_info->dev_replace.
1148 num_write_errors);
1149 success = 0;
1150 }
1151 }
1152
1153 goto out;
1154 }
1155 1112
1156 /* 1113 /*
1157 * for regular scrub, repair those pages that are errored.
1158 * In case of I/O errors in the area that is supposed to be 1114 * In case of I/O errors in the area that is supposed to be
1159 * repaired, continue by picking good copies of those pages. 1115 * repaired, continue by picking good copies of those pages.
1160 * Select the good pages from mirrors to rewrite bad pages from 1116 * Select the good pages from mirrors to rewrite bad pages from
@@ -1178,44 +1134,64 @@ nodatasum_case:
1178 * mirror, even if other 512 byte sectors in the same PAGE_SIZE 1134 * mirror, even if other 512 byte sectors in the same PAGE_SIZE
1179 * area are unreadable. 1135 * area are unreadable.
1180 */ 1136 */
1181
1182 /* can only fix I/O errors from here on */
1183 if (sblock_bad->no_io_error_seen)
1184 goto did_not_correct_error;
1185
1186 success = 1; 1137 success = 1;
1187 for (page_num = 0; page_num < sblock_bad->page_count; page_num++) { 1138 for (page_num = 0; page_num < sblock_bad->page_count;
1139 page_num++) {
1188 struct scrub_page *page_bad = sblock_bad->pagev[page_num]; 1140 struct scrub_page *page_bad = sblock_bad->pagev[page_num];
1141 struct scrub_block *sblock_other = NULL;
1189 1142
1190 if (!page_bad->io_error) 1143 /* skip no-io-error page in scrub */
1144 if (!page_bad->io_error && !sctx->is_dev_replace)
1191 continue; 1145 continue;
1192 1146
1193 for (mirror_index = 0; 1147 /* try to find no-io-error page in mirrors */
1194 mirror_index < BTRFS_MAX_MIRRORS && 1148 if (page_bad->io_error) {
1195 sblocks_for_recheck[mirror_index].page_count > 0; 1149 for (mirror_index = 0;
1196 mirror_index++) { 1150 mirror_index < BTRFS_MAX_MIRRORS &&
1197 struct scrub_block *sblock_other = sblocks_for_recheck + 1151 sblocks_for_recheck[mirror_index].page_count > 0;
1198 mirror_index; 1152 mirror_index++) {
1199 struct scrub_page *page_other = sblock_other->pagev[ 1153 if (!sblocks_for_recheck[mirror_index].
1200 page_num]; 1154 pagev[page_num]->io_error) {
1201 1155 sblock_other = sblocks_for_recheck +
1202 if (!page_other->io_error) { 1156 mirror_index;
1203 ret = scrub_repair_page_from_good_copy( 1157 break;
1204 sblock_bad, sblock_other, page_num, 0);
1205 if (0 == ret) {
1206 page_bad->io_error = 0;
1207 break; /* succeeded for this page */
1208 } 1158 }
1209 } 1159 }
1160 if (!sblock_other)
1161 success = 0;
1210 } 1162 }
1211 1163
1212 if (page_bad->io_error) { 1164 if (sctx->is_dev_replace) {
1213 /* did not find a mirror to copy the page from */ 1165 /*
1214 success = 0; 1166 * did not find a mirror to fetch the page
1167 * from. scrub_write_page_to_dev_replace()
1168 * handles this case (page->io_error), by
1169 * filling the block with zeros before
1170 * submitting the write request
1171 */
1172 if (!sblock_other)
1173 sblock_other = sblock_bad;
1174
1175 if (scrub_write_page_to_dev_replace(sblock_other,
1176 page_num) != 0) {
1177 btrfs_dev_replace_stats_inc(
1178 &sctx->dev_root->
1179 fs_info->dev_replace.
1180 num_write_errors);
1181 success = 0;
1182 }
1183 } else if (sblock_other) {
1184 ret = scrub_repair_page_from_good_copy(sblock_bad,
1185 sblock_other,
1186 page_num, 0);
1187 if (0 == ret)
1188 page_bad->io_error = 0;
1189 else
1190 success = 0;
1215 } 1191 }
1216 } 1192 }
1217 1193
1218 if (success) { 1194 if (success && !sctx->is_dev_replace) {
1219 if (is_metadata || have_csum) { 1195 if (is_metadata || have_csum) {
1220 /* 1196 /*
1221 * need to verify the checksum now that all 1197 * need to verify the checksum now that all