@@ -468,17 +468,15 @@ static void raid10_end_write_request(struct bio *bio)
dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
if (repl)
- rdev = conf->mirrors[dev].replacement;
- if (!rdev) {
- smp_rmb();
- repl = 0;
- rdev = conf->mirrors[dev].rdev;
- }
+ rdev = r10_bio->devs[slot].replacement;
+ else
+ rdev = r10_bio->devs[slot].rdev;
/*
* this branch is our 'one mirror IO has finished' event handler:
*/
if (bio->bi_status && !discard_error) {
- if (repl)
+ /* replacement may have replaced rdev */
+ if (repl && rdev == conf->mirrors[dev].replacement)
/* Never record new bad blocks to replacement,
* just fail it.
*/
@@ -504,7 +502,10 @@ static void raid10_end_write_request(struct bio *bio)
else {
/* Fail the request */
set_bit(R10BIO_Degraded, &r10_bio->state);
- r10_bio->devs[slot].bio = NULL;
+ if (repl)
+ r10_bio->devs[slot].repl_bio = NULL;
+ else
+ r10_bio->devs[slot].bio = NULL;
to_put = bio;
dec_rdev = 1;
}
@@ -1289,15 +1290,10 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
int devnum = r10_bio->devs[n_copy].devnum;
struct bio *mbio;
- if (replacement) {
- rdev = conf->mirrors[devnum].replacement;
- if (rdev == NULL) {
- /* Replacement just got moved to main 'rdev' */
- smp_mb();
- rdev = conf->mirrors[devnum].rdev;
- }
- } else
- rdev = conf->mirrors[devnum].rdev;
+ if (replacement)
+ rdev = r10_bio->devs[n_copy].replacement;
+ else
+ rdev = r10_bio->devs[n_copy].rdev;
mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO, &mddev->bio_set);
if (replacement)
@@ -1309,8 +1305,7 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
choose_data_offset(r10_bio, rdev));
mbio->bi_end_io = raid10_end_write_request;
mbio->bi_opf = op | do_sync | do_fua;
- if (!replacement && test_bit(FailFast,
- &conf->mirrors[devnum].rdev->flags)
+ if (!replacement && test_bit(FailFast, &rdev->flags)
&& enough(conf, devnum))
mbio->bi_opf |= MD_FAILFAST;
mbio->bi_private = r10_bio;
@@ -1530,10 +1525,12 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
}
if (rdev) {
r10_bio->devs[i].bio = bio;
+ r10_bio->devs[i].rdev = rdev;
atomic_inc(&rdev->nr_pending);
}
if (rrdev) {
r10_bio->devs[i].repl_bio = bio;
+ r10_bio->devs[i].replacement = rrdev;
atomic_inc(&rrdev->nr_pending);
}
}
@@ -3051,9 +3048,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
} else {
bool fail = false;
for (m = 0; m < conf->copies; m++) {
- int dev = r10_bio->devs[m].devnum;
struct bio *bio = r10_bio->devs[m].bio;
- rdev = conf->mirrors[dev].rdev;
+ rdev = r10_bio->devs[m].rdev;
if (bio == IO_MADE_GOOD) {
rdev_clear_badblocks(
rdev,
@@ -3070,7 +3066,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_dec_pending(rdev, conf->mddev);
}
bio = r10_bio->devs[m].repl_bio;
- rdev = conf->mirrors[dev].replacement;
+ rdev = r10_bio->devs[m].replacement;
if (rdev && bio == IO_MADE_GOOD) {
rdev_clear_badblocks(
rdev,