Commit fae8cc5e authored by NeilBrown's avatar NeilBrown

md/raid10: fix handling of error on last working device in array.

If we get a read error on the last working device in a RAID10 which
contains the target block, then we don't fail the device (which is
good) but we don't abort retries, which is wrong.
We end up in an infinite loop retrying the read on the one device.

This patch fixes the problem in two places:
1/ in raid10_end_read_request we don't even ask for a retry if this
   was the last usable device.  This is efficient but a little racy
   and will sometimes retry when it should not.

2/ in handle_read_error we are careful to exclude any device from
   retry which we tried to mark as faulty (that might have failed if
   it was the last device).  This is race-free but less efficient.
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
parent f53e29fc
...@@ -67,6 +67,7 @@ static int max_queued_requests = 1024; ...@@ -67,6 +67,7 @@ static int max_queued_requests = 1024;
static void allow_barrier(struct r10conf *conf); static void allow_barrier(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf); static void lower_barrier(struct r10conf *conf);
static int enough(struct r10conf *conf, int ignore);
static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data) static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
{ {
...@@ -347,6 +348,19 @@ static void raid10_end_read_request(struct bio *bio, int error) ...@@ -347,6 +348,19 @@ static void raid10_end_read_request(struct bio *bio, int error)
* wait for the 'master' bio. * wait for the 'master' bio.
*/ */
set_bit(R10BIO_Uptodate, &r10_bio->state); set_bit(R10BIO_Uptodate, &r10_bio->state);
} else {
/* If all other devices that store this block have
* failed, we want to return the error upwards rather
* than fail the last device. Here we redefine
* "uptodate" to mean "Don't want to retry"
*/
unsigned long flags;
spin_lock_irqsave(&conf->device_lock, flags);
if (!enough(conf, rdev->raid_disk))
uptodate = 1;
spin_unlock_irqrestore(&conf->device_lock, flags);
}
if (uptodate) {
raid_end_bio_io(r10_bio); raid_end_bio_io(r10_bio);
rdev_dec_pending(rdev, conf->mddev); rdev_dec_pending(rdev, conf->mddev);
} else { } else {
...@@ -2052,6 +2066,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 ...@@ -2052,6 +2066,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
"md/raid10:%s: %s: Failing raid device\n", "md/raid10:%s: %s: Failing raid device\n",
mdname(mddev), b); mdname(mddev), b);
md_error(mddev, conf->mirrors[d].rdev); md_error(mddev, conf->mirrors[d].rdev);
r10_bio->devs[r10_bio->read_slot].bio = IO_BLOCKED;
return; return;
} }
...@@ -2105,8 +2120,11 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 ...@@ -2105,8 +2120,11 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
rdev, rdev,
r10_bio->devs[r10_bio->read_slot].addr r10_bio->devs[r10_bio->read_slot].addr
+ sect, + sect,
s, 0)) s, 0)) {
md_error(mddev, rdev); md_error(mddev, rdev);
r10_bio->devs[r10_bio->read_slot].bio
= IO_BLOCKED;
}
break; break;
} }
...@@ -2299,17 +2317,20 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio) ...@@ -2299,17 +2317,20 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
* This is all done synchronously while the array is * This is all done synchronously while the array is
* frozen. * frozen.
*/ */
bio = r10_bio->devs[slot].bio;
bdevname(bio->bi_bdev, b);
bio_put(bio);
r10_bio->devs[slot].bio = NULL;
if (mddev->ro == 0) { if (mddev->ro == 0) {
freeze_array(conf); freeze_array(conf);
fix_read_error(conf, mddev, r10_bio); fix_read_error(conf, mddev, r10_bio);
unfreeze_array(conf); unfreeze_array(conf);
} } else
r10_bio->devs[slot].bio = IO_BLOCKED;
rdev_dec_pending(rdev, mddev); rdev_dec_pending(rdev, mddev);
bio = r10_bio->devs[slot].bio;
bdevname(bio->bi_bdev, b);
r10_bio->devs[slot].bio =
mddev->ro ? IO_BLOCKED : NULL;
read_more: read_more:
rdev = read_balance(conf, r10_bio, &max_sectors); rdev = read_balance(conf, r10_bio, &max_sectors);
if (rdev == NULL) { if (rdev == NULL) {
...@@ -2318,13 +2339,10 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio) ...@@ -2318,13 +2339,10 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
mdname(mddev), b, mdname(mddev), b,
(unsigned long long)r10_bio->sector); (unsigned long long)r10_bio->sector);
raid_end_bio_io(r10_bio); raid_end_bio_io(r10_bio);
bio_put(bio);
return; return;
} }
do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC); do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC);
if (bio)
bio_put(bio);
slot = r10_bio->read_slot; slot = r10_bio->read_slot;
printk_ratelimited( printk_ratelimited(
KERN_ERR KERN_ERR
...@@ -2360,7 +2378,6 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio) ...@@ -2360,7 +2378,6 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
mbio->bi_phys_segments++; mbio->bi_phys_segments++;
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
generic_make_request(bio); generic_make_request(bio);
bio = NULL;
r10_bio = mempool_alloc(conf->r10bio_pool, r10_bio = mempool_alloc(conf->r10bio_pool,
GFP_NOIO); GFP_NOIO);
......
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