diff --git a/drivers/md/md.c b/drivers/md/md.c
index c2ff77ccec50..c7aae66c6f9b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3483,7 +3483,7 @@ static void md_safemode_timeout(unsigned long data)
 	if (!atomic_read(&mddev->writes_pending)) {
 		mddev->safemode = 1;
 		if (mddev->external)
-			sysfs_notify(&mddev->kobj, NULL, "array_state");
+			set_bit(MD_NOTIFY_ARRAY_STATE, &mddev->flags);
 	}
 	md_wakeup_thread(mddev->thread);
 }
@@ -5996,7 +5996,8 @@ static int remove_and_add_spares(mddev_t *mddev)
 	if (mddev->degraded) {
 		rdev_for_each(rdev, rtmp, mddev) {
 			if (rdev->raid_disk >= 0 &&
-			    !test_bit(In_sync, &rdev->flags))
+			    !test_bit(In_sync, &rdev->flags) &&
+			    !test_bit(Blocked, &rdev->flags))
 				spares++;
 			if (rdev->raid_disk < 0
 			    && !test_bit(Faulty, &rdev->flags)) {
@@ -6051,6 +6052,9 @@ void md_check_recovery(mddev_t *mddev)
 	if (mddev->bitmap)
 		bitmap_daemon_work(mddev->bitmap);
 
+	if (test_and_clear_bit(MD_NOTIFY_ARRAY_STATE, &mddev->flags))
+		sysfs_notify(&mddev->kobj, NULL, "array_state");
+
 	if (mddev->ro)
 		return;
 
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 159535d73567..d41bebb6da0f 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -215,6 +215,9 @@ static void reschedule_retry(r10bio_t *r10_bio)
 	conf->nr_queued ++;
 	spin_unlock_irqrestore(&conf->device_lock, flags);
 
+	/* wake up frozen array... */
+	wake_up(&conf->wait_barrier);
+
 	md_wakeup_thread(mddev->thread);
 }
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 55e7c56045a0..40e939675657 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2507,7 +2507,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
  *
  */
 
-static void handle_stripe5(struct stripe_head *sh)
+static bool handle_stripe5(struct stripe_head *sh)
 {
 	raid5_conf_t *conf = sh->raid_conf;
 	int disks = sh->disks, i;
@@ -2717,10 +2717,11 @@ static void handle_stripe5(struct stripe_head *sh)
 	if (sh->reconstruct_state == reconstruct_state_result) {
 		sh->reconstruct_state = reconstruct_state_idle;
 		clear_bit(STRIPE_EXPANDING, &sh->state);
-		for (i = conf->raid_disks; i--; )
+		for (i = conf->raid_disks; i--; ) {
 			set_bit(R5_Wantwrite, &sh->dev[i].flags);
-			set_bit(R5_LOCKED, &dev->flags);
+			set_bit(R5_LOCKED, &sh->dev[i].flags);
 			s.locked++;
+		}
 	}
 
 	if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) &&
@@ -2754,9 +2755,11 @@ static void handle_stripe5(struct stripe_head *sh)
 	ops_run_io(sh, &s);
 
 	return_io(return_bi);
+
+	return blocked_rdev == NULL;
 }
 
-static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
+static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
 {
 	raid6_conf_t *conf = sh->raid_conf;
 	int disks = sh->disks;
@@ -2967,14 +2970,17 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
 	ops_run_io(sh, &s);
 
 	return_io(return_bi);
+
+	return blocked_rdev == NULL;
 }
 
-static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
+/* returns true if the stripe was handled */
+static bool handle_stripe(struct stripe_head *sh, struct page *tmp_page)
 {
 	if (sh->raid_conf->level == 6)
-		handle_stripe6(sh, tmp_page);
+		return handle_stripe6(sh, tmp_page);
 	else
-		handle_stripe5(sh);
+		return handle_stripe5(sh);
 }
 
 
@@ -3692,7 +3698,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
 	clear_bit(STRIPE_INSYNC, &sh->state);
 	spin_unlock(&sh->lock);
 
-	handle_stripe(sh, NULL);
+	/* wait for any blocked device to be handled */
+	while(unlikely(!handle_stripe(sh, NULL)))
+		;
 	release_stripe(sh);
 
 	return STRIPE_SECTORS;
@@ -3811,10 +3819,8 @@ static void raid5d(mddev_t *mddev)
 
 		sh = __get_priority_stripe(conf);
 
-		if (!sh) {
-			async_tx_issue_pending_all();
+		if (!sh)
 			break;
-		}
 		spin_unlock_irq(&conf->device_lock);
 		
 		handled++;
@@ -3827,6 +3833,7 @@ static void raid5d(mddev_t *mddev)
 
 	spin_unlock_irq(&conf->device_lock);
 
+	async_tx_issue_pending_all();
 	unplug_slaves(mddev);
 
 	pr_debug("--- raid5d inactive\n");
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index 9f2549ac0e2d..c200b9a34aff 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -128,6 +128,7 @@ struct mddev_s
 #define MD_CHANGE_DEVS	0	/* Some device status has changed */
 #define MD_CHANGE_CLEAN 1	/* transition to or from 'clean' */
 #define MD_CHANGE_PENDING 2	/* superblock update in progress */
+#define MD_NOTIFY_ARRAY_STATE 3	/* atomic context wants to notify userspace */
 
 	int				ro;