md/raid1,raid10: avoid deadlock during resync/recovery.
[deliverable/linux.git] / drivers / md / raid10.c
index 58c44d6453a0bfa0fb40f155c0357e4392731999..2ae7021320e178d0b40b93fcbd24842e11c2a713 100644 (file)
@@ -863,9 +863,22 @@ static void wait_barrier(struct r10conf *conf)
        spin_lock_irq(&conf->resync_lock);
        if (conf->barrier) {
                conf->nr_waiting++;
-               wait_event_lock_irq(conf->wait_barrier, !conf->barrier,
+               /* Wait for the barrier to drop.
+                * However if there are already pending
+                * requests (preventing the barrier from
+                * rising completely), and the
+                * pre-process bio queue isn't empty,
+                * then don't wait, as we need to empty
+                * that queue to get the nr_pending
+                * count down.
+                */
+               wait_event_lock_irq(conf->wait_barrier,
+                                   !conf->barrier ||
+                                   (conf->nr_pending &&
+                                    current->bio_list &&
+                                    !bio_list_empty(current->bio_list)),
                                    conf->resync_lock,
-                                   );
+                       );
                conf->nr_waiting--;
        }
        conf->nr_pending++;
@@ -1483,7 +1496,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                 * very different from resync
                 */
                return -EBUSY;
-       if (!enough(conf, -1))
+       if (rdev->saved_raid_disk < 0 && !enough(conf, -1))
                return -EINVAL;
 
        if (rdev->raid_disk >= 0)
@@ -1682,10 +1695,8 @@ static void end_sync_write(struct bio *bio, int error)
        d = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
        if (repl)
                rdev = conf->mirrors[d].replacement;
-       if (!rdev) {
-               smp_mb();
+       else
                rdev = conf->mirrors[d].rdev;
-       }
 
        if (!uptodate) {
                if (repl)
This page took 0.025112 seconds and 5 git commands to generate.