diff options
author | NeilBrown <neilb@suse.de> | 2010-08-07 07:17:00 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2010-08-07 07:17:00 -0400 |
commit | 51e9ac77035a3dfcb6fc0a88a0d80b6f99b5edb1 (patch) | |
tree | 94167223c5711c47169db672a0ec0d23a36208b9 /drivers/md | |
parent | 69e51b449d383e97b1b9f890f8378c96e9e17346 (diff) |
md/raid10: fix deadlock with unaligned read during resync
If the 'bio_split' path in raid10-read is used while
resync/recovery is happening it is possible to deadlock.
Fix this be elevating ->nr_waiting for the duration of both
parts of the split request.
This fixes a bug that has been present since 2.6.22
but has only started manifesting recently for unknown reasons.
It is suitable for and -stable since then.
Reported-by: Justin Bronder <jsbronder@gentoo.org>
Tested-by: Justin Bronder <jsbronder@gentoo.org>
Signed-off-by: NeilBrown <neilb@suse.de>
Cc: stable@kernel.org
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: |