diff options
author | NeilBrown <neilb@suse.de> | 2012-07-02 22:13:29 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2012-07-02 22:13:29 -0400 |
commit | 5f066c632fcfd2a33f2eb7077c15c630e9f5ea5b (patch) | |
tree | 9a659a20661d4a2b13f796cd2409879c0596b5c1 | |
parent | 7c2c57c9a98bf5961e438a376486f95346f6b0c5 (diff) |
md/raid5: fix refcount problem when blocked_rdev is set.
commit 43220aa0f22cd3ce5b30246d50ccd696d119edea
md/raid5: fix a hang on device failure.
fixed a hang, but introduced a refcounting in-balance so
that if the presence of bad-blocks ever caused an rdev to
be 'blocked' we would increment the refcount on the rdev and
never decrement it.
So added the needed rdev_dec_pending when md_wait_for_blocked_rdev
is not called.
Reported-by: majianpeng <majianpeng@gmail.com>
Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r-- | drivers/md/raid5.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index befadb41a11f..62b6b3a83abf 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -3588,8 +3588,18 @@ static void handle_stripe(struct stripe_head *sh) | |||
3588 | 3588 | ||
3589 | finish: | 3589 | finish: |
3590 | /* wait for this device to become unblocked */ | 3590 | /* wait for this device to become unblocked */ |
3591 | if (conf->mddev->external && unlikely(s.blocked_rdev)) | 3591 | if (unlikely(s.blocked_rdev)) { |
3592 | md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev); | 3592 | if (conf->mddev->external) |
3593 | md_wait_for_blocked_rdev(s.blocked_rdev, | ||
3594 | conf->mddev); | ||
3595 | else | ||
3596 | /* Internal metadata will immediately | ||
3597 | * be written by raid5d, so we don't | ||
3598 | * need to wait here. | ||
3599 | */ | ||
3600 | rdev_dec_pending(s.blocked_rdev, | ||
3601 | conf->mddev); | ||
3602 | } | ||
3593 | 3603 | ||
3594 | if (s.handle_bad_blocks) | 3604 | if (s.handle_bad_blocks) |
3595 | for (i = disks; i--; ) { | 3605 | for (i = disks; i--; ) { |