Commit 7c785b7a authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] md: fix a plug/unplug race in raid5

When a device is unplugged, requests are moved from one or two (depending on
whether a bitmap is in use) queues to the main request queue.

So whenever requests are put on either of those queues, we should make sure
the raid5 array is 'plugged'.  However we don't.  We currently plug the raid5
queue just before putting requests on queues, so there is room for a race.  If
something unplugs the queue at just the wrong time, requests will be left on
the queue and nothing will want to unplug them.  Normally something else will
plug and unplug the queue fairly soon, but there is a risk that nothing will.
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ff4e8d9a
...@@ -88,12 +88,14 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) ...@@ -88,12 +88,14 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
BUG_ON(!list_empty(&sh->lru)); BUG_ON(!list_empty(&sh->lru));
BUG_ON(atomic_read(&conf->active_stripes)==0); BUG_ON(atomic_read(&conf->active_stripes)==0);
if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_HANDLE, &sh->state)) {
if (test_bit(STRIPE_DELAYED, &sh->state)) if (test_bit(STRIPE_DELAYED, &sh->state)) {
list_add_tail(&sh->lru, &conf->delayed_list); list_add_tail(&sh->lru, &conf->delayed_list);
else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && blk_plug_device(conf->mddev->queue);
conf->seq_write == sh->bm_seq) } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
conf->seq_write == sh->bm_seq) {
list_add_tail(&sh->lru, &conf->bitmap_list); list_add_tail(&sh->lru, &conf->bitmap_list);
else { blk_plug_device(conf->mddev->queue);
} else {
clear_bit(STRIPE_BIT_DELAY, &sh->state); clear_bit(STRIPE_BIT_DELAY, &sh->state);
list_add_tail(&sh->lru, &conf->handle_list); list_add_tail(&sh->lru, &conf->handle_list);
} }
...@@ -2555,13 +2557,6 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk, ...@@ -2555,13 +2557,6 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret; return ret;
} }
static inline void raid5_plug_device(raid5_conf_t *conf)
{
spin_lock_irq(&conf->device_lock);
blk_plug_device(conf->mddev->queue);
spin_unlock_irq(&conf->device_lock);
}
static int make_request(request_queue_t *q, struct bio * bi) static int make_request(request_queue_t *q, struct bio * bi)
{ {
mddev_t *mddev = q->queuedata; mddev_t *mddev = q->queuedata;
...@@ -2671,7 +2666,6 @@ static int make_request(request_queue_t *q, struct bio * bi) ...@@ -2671,7 +2666,6 @@ static int make_request(request_queue_t *q, struct bio * bi)
goto retry; goto retry;
} }
finish_wait(&conf->wait_for_overlap, &w); finish_wait(&conf->wait_for_overlap, &w);
raid5_plug_device(conf);
handle_stripe(sh, NULL); handle_stripe(sh, NULL);
release_stripe(sh); release_stripe(sh);
} else { } else {
......
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