| From 51e9ac77035a3dfcb6fc0a88a0d80b6f99b5edb1 Mon Sep 17 00:00:00 2001 |
| From: NeilBrown <neilb@suse.de> |
| Date: Sat, 7 Aug 2010 21:17:00 +1000 |
| Subject: md/raid10: fix deadlock with unaligned read during resync |
| |
| From: NeilBrown <neilb@suse.de> |
| |
| commit 51e9ac77035a3dfcb6fc0a88a0d80b6f99b5edb1 upstream. |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/md/raid10.c | 18 ++++++++++++++++++ |
| 1 file changed, 18 insertions(+) |
| |
| --- a/drivers/md/raid10.c |
| +++ b/drivers/md/raid10.c |
| @@ -825,11 +825,29 @@ static int make_request(mddev_t *mddev, |
| */ |
| bp = bio_split(bio, |
| chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); |
| + |
| + /* Each of these 'make_request' calls will call 'wait_barrier'. |
| + * If the first succeeds but the second blocks due to the resync |
| + * thread raising the barrier, we will deadlock because the |
| + * IO to the underlying device will be queued in generic_make_request |
| + * and will never complete, so will never reduce nr_pending. |
| + * So increment nr_waiting here so no new raise_barriers will |
| + * succeed, and so the second wait_barrier cannot block. |
| + */ |
| + spin_lock_irq(&conf->resync_lock); |
| + conf->nr_waiting++; |
| + spin_unlock_irq(&conf->resync_lock); |
| + |
| if (make_request(mddev, &bp->bio1)) |
| generic_make_request(&bp->bio1); |
| if (make_request(mddev, &bp->bio2)) |
| generic_make_request(&bp->bio2); |
| |
| + spin_lock_irq(&conf->resync_lock); |
| + conf->nr_waiting--; |
| + wake_up(&conf->wait_barrier); |
| + spin_unlock_irq(&conf->resync_lock); |
| + |
| bio_pair_release(bp); |
| return 0; |
| bad_map: |