diff options
author | NeilBrown <neilb@suse.de> | 2013-02-25 12:38:29 +1100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-03-14 11:26:22 -0700 |
commit | 71192d4685c1a1fbaff5a1c6023095901bbb1cee (patch) | |
tree | d3e6fe5b8786067b0715a566ec761353b0a2af78 /drivers/md | |
parent | 5260b2b544e14287a9d6eab457d89f1658356102 (diff) | |
download | linux-stable-71192d4685c1a1fbaff5a1c6023095901bbb1cee.tar.gz linux-stable-71192d4685c1a1fbaff5a1c6023095901bbb1cee.tar.bz2 linux-stable-71192d4685c1a1fbaff5a1c6023095901bbb1cee.zip |
md/raid1,raid10: fix deadlock with freeze_array()
commit ee0b0244030434cdda26777bfb98962447e080cd upstream.
When raid1/raid10 needs to fix a read error, it first drains
all pending requests by calling freeze_array().
This calls flush_pending_writes() if it needs to sleep,
but some writes may be pending in a per-process plug rather
than in the per-array request queue.
When raid1{,0}_unplug() moves the request from the per-process
plug to the per-array request queue (from which
flush_pending_writes() can flush them), it needs to wake up
freeze_array(), or freeze_array() will never flush them and so
it will block forever.
So add the requires wake_up() calls.
This bug was introduced by commit
f54a9d0e59c4bea3db733921ca9147612a6f292c
for raid1 and a similar commit for RAID10, and so has been present
since linux-3.6. As the bug causes a deadlock I believe this fix is
suitable for -stable.
Reported-by: Tregaron Bayly <tbayly@bluehost.com>
Tested-by: Tregaron Bayly <tbayly@bluehost.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/raid1.c | 1 | ||||
-rw-r--r-- | drivers/md/raid10.c | 1 |
2 files changed, 2 insertions, 0 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d5bddfc4010e..75b1f898792c 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -967,6 +967,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) bio_list_merge(&conf->pending_bio_list, &plug->pending); conf->pending_count += plug->pending_cnt; spin_unlock_irq(&conf->device_lock); + wake_up(&conf->wait_barrier); md_wakeup_thread(mddev->thread); kfree(plug); return; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 64d48249c03b..8d925dc78828 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1073,6 +1073,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) bio_list_merge(&conf->pending_bio_list, &plug->pending); conf->pending_count += plug->pending_cnt; spin_unlock_irq(&conf->device_lock); + wake_up(&conf->wait_barrier); md_wakeup_thread(mddev->thread); kfree(plug); return; |