Commit e875ecea authored by NeilBrown's avatar NeilBrown

md/raid10 record bad blocks as needed during recovery.

When recovering one or more devices, if all the good devices have
bad blocks we should record a bad block on the device being rebuilt.

If this fails, we need to abort the recovery.

To ensure we don't think that we aborted later than we actually did,
we need to move the check for MD_RECOVERY_INTR earlier in md_do_sync,
in particular before mddev->curr_resync is updated.
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
parent 40c356ce
...@@ -7165,11 +7165,14 @@ void md_do_sync(mddev_t *mddev) ...@@ -7165,11 +7165,14 @@ void md_do_sync(mddev_t *mddev)
atomic_add(sectors, &mddev->recovery_active); atomic_add(sectors, &mddev->recovery_active);
} }
if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
break;
j += sectors; j += sectors;
if (j>1) mddev->curr_resync = j; if (j>1) mddev->curr_resync = j;
mddev->curr_mark_cnt = io_sectors; mddev->curr_mark_cnt = io_sectors;
if (last_check == 0) if (last_check == 0)
/* this is the earliers that rebuilt will be /* this is the earliest that rebuild will be
* visible in /proc/mdstat * visible in /proc/mdstat
*/ */
md_new_event(mddev); md_new_event(mddev);
...@@ -7178,10 +7181,6 @@ void md_do_sync(mddev_t *mddev) ...@@ -7178,10 +7181,6 @@ void md_do_sync(mddev_t *mddev)
continue; continue;
last_check = io_sectors; last_check = io_sectors;
if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
break;
repeat: repeat:
if (time_after_eq(jiffies, mark[last_mark] + SYNC_MARK_STEP )) { if (time_after_eq(jiffies, mark[last_mark] + SYNC_MARK_STEP )) {
/* step marks */ /* step marks */
......
...@@ -2005,7 +2005,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, ...@@ -2005,7 +2005,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
max_sync = RESYNC_PAGES << (PAGE_SHIFT-9); max_sync = RESYNC_PAGES << (PAGE_SHIFT-9);
if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
/* recovery... the complicated one */ /* recovery... the complicated one */
int j, k; int j;
r10_bio = NULL; r10_bio = NULL;
for (i=0 ; i<conf->raid_disks; i++) { for (i=0 ; i<conf->raid_disks; i++) {
...@@ -2013,6 +2013,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, ...@@ -2013,6 +2013,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
r10bio_t *rb2; r10bio_t *rb2;
sector_t sect; sector_t sect;
int must_sync; int must_sync;
int any_working;
if (conf->mirrors[i].rdev == NULL || if (conf->mirrors[i].rdev == NULL ||
test_bit(In_sync, &conf->mirrors[i].rdev->flags)) test_bit(In_sync, &conf->mirrors[i].rdev->flags))
...@@ -2064,7 +2065,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, ...@@ -2064,7 +2065,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
must_sync = bitmap_start_sync(mddev->bitmap, sect, must_sync = bitmap_start_sync(mddev->bitmap, sect,
&sync_blocks, still_degraded); &sync_blocks, still_degraded);
any_working = 0;
for (j=0; j<conf->copies;j++) { for (j=0; j<conf->copies;j++) {
int k;
int d = r10_bio->devs[j].devnum; int d = r10_bio->devs[j].devnum;
mdk_rdev_t *rdev; mdk_rdev_t *rdev;
sector_t sector, first_bad; sector_t sector, first_bad;
...@@ -2073,6 +2076,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, ...@@ -2073,6 +2076,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
!test_bit(In_sync, &conf->mirrors[d].rdev->flags)) !test_bit(In_sync, &conf->mirrors[d].rdev->flags))
continue; continue;
/* This is where we read from */ /* This is where we read from */
any_working = 1;
rdev = conf->mirrors[d].rdev; rdev = conf->mirrors[d].rdev;
sector = r10_bio->devs[j].addr; sector = r10_bio->devs[j].addr;
...@@ -2121,16 +2125,35 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, ...@@ -2121,16 +2125,35 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
break; break;
} }
if (j == conf->copies) { if (j == conf->copies) {
/* Cannot recover, so abort the recovery */ /* Cannot recover, so abort the recovery or
* record a bad block */
put_buf(r10_bio); put_buf(r10_bio);
if (rb2) if (rb2)
atomic_dec(&rb2->remaining); atomic_dec(&rb2->remaining);
r10_bio = rb2; r10_bio = rb2;
if (any_working) {
/* problem is that there are bad blocks
* on other device(s)
*/
int k;
for (k = 0; k < conf->copies; k++)
if (r10_bio->devs[k].devnum == i)
break;
if (!rdev_set_badblocks(
conf->mirrors[i].rdev,
r10_bio->devs[k].addr,
max_sync, 0))
any_working = 0;
}
if (!any_working) {
if (!test_and_set_bit(MD_RECOVERY_INTR, if (!test_and_set_bit(MD_RECOVERY_INTR,
&mddev->recovery)) &mddev->recovery))
printk(KERN_INFO "md/raid10:%s: insufficient " printk(KERN_INFO "md/raid10:%s: insufficient "
"working devices for recovery.\n", "working devices for recovery.\n",
mdname(mddev)); mdname(mddev));
conf->mirrors[i].recovery_disabled
= mddev->recovery_disabled;
}
break; break;
} }
} }
...@@ -2290,7 +2313,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, ...@@ -2290,7 +2313,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
return sectors_skipped + nr_sectors; return sectors_skipped + nr_sectors;
giveup: giveup:
/* There is nowhere to write, so all non-sync /* There is nowhere to write, so all non-sync
* drives must be failed, so try the next chunk... * drives must be failed or in resync, all drives
* have a bad block, so try the next chunk...
*/ */
if (sector_nr + max_sync < max_sector) if (sector_nr + max_sync < max_sector)
max_sector = sector_nr + max_sync; max_sector = sector_nr + max_sync;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment