md/raid5: fix refcount problem when blocked_rdev is set.
authorNeilBrown <neilb@suse.de>
Tue, 3 Jul 2012 02:13:29 +0000 (12:13 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 3 Jul 2012 02:13:29 +0000 (12:13 +1000)
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>
drivers/md/raid5.c

index befadb41a11f0c77bf68cd7bda5af1dd7ffef785..62b6b3a83abf7f7bfab954b11f1a3087a3ec3f8b 100644 (file)
@@ -3588,8 +3588,18 @@ static void handle_stripe(struct stripe_head *sh)
 
 finish:
        /* wait for this device to become unblocked */
-       if (conf->mddev->external && unlikely(s.blocked_rdev))
-               md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev);
+       if (unlikely(s.blocked_rdev)) {
+               if (conf->mddev->external)
+                       md_wait_for_blocked_rdev(s.blocked_rdev,
+                                                conf->mddev);
+               else
+                       /* Internal metadata will immediately
+                        * be written by raid5d, so we don't
+                        * need to wait here.
+                        */
+                       rdev_dec_pending(s.blocked_rdev,
+                                        conf->mddev);
+       }
 
        if (s.handle_bad_blocks)
                for (i = disks; i--; ) {