diff options
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/raid10.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 42e64e4e5e25..d1d689126346 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -825,11 +825,29 @@ static int make_request(mddev_t *mddev, struct bio * bio) | |||
825 | */ | 825 | */ |
826 | bp = bio_split(bio, | 826 | bp = bio_split(bio, |
827 | chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); | 827 | chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); |
828 | |||
829 | /* Each of these 'make_request' calls will call 'wait_barrier'. | ||
830 | * If the first succeeds but the second blocks due to the resync | ||
831 | * thread raising the barrier, we will deadlock because the | ||
832 | * IO to the underlying device will be queued in generic_make_request | ||
833 | * and will never complete, so will never reduce nr_pending. | ||
834 | * So increment nr_waiting here so no new raise_barriers will | ||
835 | * succeed, and so the second wait_barrier cannot block. | ||
836 | */ | ||
837 | spin_lock_irq(&conf->resync_lock); | ||
838 | conf->nr_waiting++; | ||
839 | spin_unlock_irq(&conf->resync_lock); | ||
840 | |||
828 | if (make_request(mddev, &bp->bio1)) | 841 | if (make_request(mddev, &bp->bio1)) |
829 | generic_make_request(&bp->bio1); | 842 | generic_make_request(&bp->bio1); |
830 | if (make_request(mddev, &bp->bio2)) | 843 | if (make_request(mddev, &bp->bio2)) |
831 | generic_make_request(&bp->bio2); | 844 | generic_make_request(&bp->bio2); |
832 | 845 | ||
846 | spin_lock_irq(&conf->resync_lock); | ||
847 | conf->nr_waiting--; | ||
848 | wake_up(&conf->wait_barrier); | ||
849 | spin_unlock_irq(&conf->resync_lock); | ||
850 | |||
833 | bio_pair_release(bp); | 851 | bio_pair_release(bp); |
834 | return 0; | 852 | return 0; |
835 | bad_map: | 853 | bad_map: |