md/raid1{,0}: fix deadlock in bitmap_unplug.
authorNeilBrown <neilb@suse.de>
Tue, 27 Nov 2012 01:14:40 +0000 (12:14 +1100)
committerNeilBrown <neilb@suse.de>
Tue, 27 Nov 2012 01:14:40 +0000 (12:14 +1100)
If the raid1 or raid10 unplug function gets called
from a make_request function (which is very possible) when
there are bios on the current->bio_list list, then it will not
be able to successfully call bitmap_unplug() and it could
need to submit more bios and wait for them to complete.
But they won't complete while current->bio_list is non-empty.

So detect that case and handle the unplugging off to another thread
just like we already do when called from within the scheduler.

RAID1 version of bug was introduced in 3.6, so that part of fix is
suitable for 3.6.y.  RAID10 part won't apply.

Cc: stable@vger.kernel.org
Reported-by: Torsten Kaiser <just.for.lkml@googlemail.com>
Reported-by: Peter Maloney <peter.maloney@brockmann-consult.de>
Signed-off-by: NeilBrown <neilb@suse.de>
drivers/md/raid1.c
drivers/md/raid10.c

index 636bae0405e8167edcec328e5759b3f949dd0876..a0f73092176e06cd736885496e02a5fab601dffe 100644 (file)
@@ -963,7 +963,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
        struct r1conf *conf = mddev->private;
        struct bio *bio;
 
-       if (from_schedule) {
+       if (from_schedule || current->bio_list) {
                spin_lock_irq(&conf->device_lock);
                bio_list_merge(&conf->pending_bio_list, &plug->pending);
                conf->pending_count += plug->pending_cnt;
index 0d5d0ff2c0f7beb47a02bd4692273b31369b2bc5..c9acbd717131ba8e28f4362d3e1aca967922ede8 100644 (file)
@@ -1069,7 +1069,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
        struct r10conf *conf = mddev->private;
        struct bio *bio;
 
-       if (from_schedule) {
+       if (from_schedule || current->bio_list) {
                spin_lock_irq(&conf->device_lock);
                bio_list_merge(&conf->pending_bio_list, &plug->pending);
                conf->pending_count += plug->pending_cnt;