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 | |
| 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
| -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: |
