md/raid5: Move code for finishing a reconstruction into handle_stripe.
[pandora-kernel.git] / drivers / md / raid5.c
index b72edf3..cd6f04f 100644 (file)
@@ -1020,12 +1020,12 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
                if (test_and_clear_bit(R5_Wantdrain, &dev->flags)) {
                        struct bio *wbi;
 
-                       spin_lock(&sh->lock);
+                       spin_lock_irq(&sh->raid_conf->device_lock);
                        chosen = dev->towrite;
                        dev->towrite = NULL;
                        BUG_ON(dev->written);
                        wbi = dev->written = chosen;
-                       spin_unlock(&sh->lock);
+                       spin_unlock_irq(&sh->raid_conf->device_lock);
 
                        while (wbi && wbi->bi_sector <
                                dev->sector + STRIPE_SECTORS) {
@@ -1315,12 +1315,11 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request)
 static int grow_one_stripe(raid5_conf_t *conf)
 {
        struct stripe_head *sh;
-       sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+       sh = kmem_cache_zalloc(conf->slab_cache, GFP_KERNEL);
        if (!sh)
                return 0;
-       memset(sh, 0, sizeof(*sh) + (conf->pool_size-1)*sizeof(struct r5dev));
+
        sh->raid_conf = conf;
-       spin_lock_init(&sh->lock);
        #ifdef CONFIG_MULTICORE_RAID456
        init_waitqueue_head(&sh->ops.wait_for_ops);
        #endif
@@ -1435,14 +1434,11 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
                return -ENOMEM;
 
        for (i = conf->max_nr_stripes; i; i--) {
-               nsh = kmem_cache_alloc(sc, GFP_KERNEL);
+               nsh = kmem_cache_zalloc(sc, GFP_KERNEL);
                if (!nsh)
                        break;
 
-               memset(nsh, 0, sizeof(*nsh) + (newsize-1)*sizeof(struct r5dev));
-
                nsh->raid_conf = conf;
-               spin_lock_init(&nsh->lock);
                #ifdef CONFIG_MULTICORE_RAID456
                init_waitqueue_head(&nsh->ops.wait_for_ops);
                #endif
@@ -2143,12 +2139,11 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
        raid5_conf_t *conf = sh->raid_conf;
        int firstwrite=0;
 
-       pr_debug("adding bh b#%llu to stripe s#%llu\n",
+       pr_debug("adding bi b#%llu to stripe s#%llu\n",
                (unsigned long long)bi->bi_sector,
                (unsigned long long)sh->sector);
 
 
-       spin_lock(&sh->lock);
        spin_lock_irq(&conf->device_lock);
        if (forwrite) {
                bip = &sh->dev[dd_idx].towrite;
@@ -2169,19 +2164,6 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
                bi->bi_next = *bip;
        *bip = bi;
        bi->bi_phys_segments++;
-       spin_unlock_irq(&conf->device_lock);
-       spin_unlock(&sh->lock);
-
-       pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
-               (unsigned long long)bi->bi_sector,
-               (unsigned long long)sh->sector, dd_idx);
-
-       if (conf->mddev->bitmap && firstwrite) {
-               bitmap_startwrite(conf->mddev->bitmap, sh->sector,
-                                 STRIPE_SECTORS, 0);
-               sh->bm_seq = conf->seq_flush+1;
-               set_bit(STRIPE_BIT_DELAY, &sh->state);
-       }
 
        if (forwrite) {
                /* check if page is covered */
@@ -2196,12 +2178,23 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
                if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS)
                        set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags);
        }
+       spin_unlock_irq(&conf->device_lock);
+
+       pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
+               (unsigned long long)(*bip)->bi_sector,
+               (unsigned long long)sh->sector, dd_idx);
+
+       if (conf->mddev->bitmap && firstwrite) {
+               bitmap_startwrite(conf->mddev->bitmap, sh->sector,
+                                 STRIPE_SECTORS, 0);
+               sh->bm_seq = conf->seq_flush+1;
+               set_bit(STRIPE_BIT_DELAY, &sh->state);
+       }
        return 1;
 
  overlap:
        set_bit(R5_Overlap, &sh->dev[dd_idx].flags);
        spin_unlock_irq(&conf->device_lock);
-       spin_unlock(&sh->lock);
        return 0;
 }
 
@@ -2325,7 +2318,7 @@ static int fetch_block5(struct stripe_head *sh, struct stripe_head_state *s,
                        int disk_idx, int disks)
 {
        struct r5dev *dev = &sh->dev[disk_idx];
-       struct r5dev *failed_dev = &sh->dev[s->failed_num];
+       struct r5dev *failed_dev = &sh->dev[s->failed_num[0]];
 
        /* is the data in this block needed, and can we get it? */
        if (!test_bit(R5_LOCKED, &dev->flags) &&
@@ -2341,7 +2334,7 @@ static int fetch_block5(struct stripe_head *sh, struct stripe_head_state *s,
                 * otherwise read it if the backing disk is insync
                 */
                if ((s->uptodate == disks - 1) &&
-                   (s->failed && disk_idx == s->failed_num)) {
+                   (s->failed && disk_idx == s->failed_num[0])) {
                        set_bit(STRIPE_COMPUTE_RUN, &sh->state);
                        set_bit(STRIPE_OP_COMPUTE_BLK, &s->ops_request);
                        set_bit(R5_Wantcompute, &dev->flags);
@@ -2395,11 +2388,11 @@ static void handle_stripe_fill5(struct stripe_head *sh,
  * 0 to tell the loop in handle_stripe_fill6 to continue
  */
 static int fetch_block6(struct stripe_head *sh, struct stripe_head_state *s,
-                        struct r6_state *r6s, int disk_idx, int disks)
+                       int disk_idx, int disks)
 {
        struct r5dev *dev = &sh->dev[disk_idx];
-       struct r5dev *fdev[2] = { &sh->dev[r6s->failed_num[0]],
-                                 &sh->dev[r6s->failed_num[1]] };
+       struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]],
+                                 &sh->dev[s->failed_num[1]] };
 
        if (!test_bit(R5_LOCKED, &dev->flags) &&
            !test_bit(R5_UPTODATE, &dev->flags) &&
@@ -2416,8 +2409,8 @@ static int fetch_block6(struct stripe_head *sh, struct stripe_head_state *s,
                BUG_ON(test_bit(R5_Wantcompute, &dev->flags));
                BUG_ON(test_bit(R5_Wantread, &dev->flags));
                if ((s->uptodate == disks - 1) &&
-                   (s->failed && (disk_idx == r6s->failed_num[0] ||
-                                  disk_idx == r6s->failed_num[1]))) {
+                   (s->failed && (disk_idx == s->failed_num[0] ||
+                                  disk_idx == s->failed_num[1]))) {
                        /* have disk failed, and we're requested to fetch it;
                         * do compute it
                         */
@@ -2472,7 +2465,7 @@ static int fetch_block6(struct stripe_head *sh, struct stripe_head_state *s,
  * handle_stripe_fill6 - read or compute data to satisfy pending requests.
  */
 static void handle_stripe_fill6(struct stripe_head *sh,
-                       struct stripe_head_state *s, struct r6_state *r6s,
+                       struct stripe_head_state *s,
                        int disks)
 {
        int i;
@@ -2484,7 +2477,7 @@ static void handle_stripe_fill6(struct stripe_head *sh,
        if (!test_bit(STRIPE_COMPUTE_RUN, &sh->state) && !sh->check_state &&
            !sh->reconstruct_state)
                for (i = disks; i--; )
-                       if (fetch_block6(sh, s, r6s, i, disks))
+                       if (fetch_block6(sh, s, i, disks))
                                break;
        set_bit(STRIPE_HANDLE, &sh->state);
 }
@@ -2632,7 +2625,7 @@ static void handle_stripe_dirtying5(raid5_conf_t *conf,
 
 static void handle_stripe_dirtying6(raid5_conf_t *conf,
                struct stripe_head *sh, struct stripe_head_state *s,
-               struct r6_state *r6s, int disks)
+               int disks)
 {
        int rcw = 0, pd_idx = sh->pd_idx, i;
        int qd_idx = sh->qd_idx;
@@ -2695,7 +2688,7 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
                        s->uptodate--;
                        break;
                }
-               dev = &sh->dev[s->failed_num];
+               dev = &sh->dev[s->failed_num[0]];
                /* fall through */
        case check_state_compute_result:
                sh->check_state = check_state_idle;
@@ -2767,7 +2760,7 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
 
 static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
                                  struct stripe_head_state *s,
-                                 struct r6_state *r6s, int disks)
+                                 int disks)
 {
        int pd_idx = sh->pd_idx;
        int qd_idx = sh->qd_idx;
@@ -2786,14 +2779,14 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
        switch (sh->check_state) {
        case check_state_idle:
                /* start a new check operation if there are < 2 failures */
-               if (s->failed == r6s->q_failed) {
+               if (s->failed == s->q_failed) {
                        /* The only possible failed device holds Q, so it
                         * makes sense to check P (If anything else were failed,
                         * we would have used P to recreate it).
                         */
                        sh->check_state = check_state_run;
                }
-               if (!r6s->q_failed && s->failed < 2) {
+               if (!s->q_failed && s->failed < 2) {
                        /* Q is not failed, and we didn't use it to generate
                         * anything, so it makes sense to check it
                         */
@@ -2835,13 +2828,13 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
                 */
                BUG_ON(s->uptodate < disks - 1); /* We don't need Q to recover */
                if (s->failed == 2) {
-                       dev = &sh->dev[r6s->failed_num[1]];
+                       dev = &sh->dev[s->failed_num[1]];
                        s->locked++;
                        set_bit(R5_LOCKED, &dev->flags);
                        set_bit(R5_Wantwrite, &dev->flags);
                }
                if (s->failed >= 1) {
-                       dev = &sh->dev[r6s->failed_num[0]];
+                       dev = &sh->dev[s->failed_num[0]];
                        s->locked++;
                        set_bit(R5_LOCKED, &dev->flags);
                        set_bit(R5_Wantwrite, &dev->flags);
@@ -2928,8 +2921,7 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
        }
 }
 
-static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
-                               struct r6_state *r6s)
+static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh)
 {
        int i;
 
@@ -2971,7 +2963,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
                        set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
                        for (j = 0; j < conf->raid_disks; j++)
                                if (j != sh2->pd_idx &&
-                                   (!r6s || j != sh2->qd_idx) &&
+                                   j != sh2->qd_idx &&
                                    !test_bit(R5_Expanded, &sh2->dev[j].flags))
                                        break;
                        if (j == conf->raid_disks) {
@@ -3006,33 +2998,16 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
  *
  */
 
-static void handle_stripe5(struct stripe_head *sh)
+static int handle_stripe5(struct stripe_head *sh, struct stripe_head_state *s)
 {
        raid5_conf_t *conf = sh->raid_conf;
        int disks = sh->disks, i;
-       struct bio *return_bi = NULL;
-       struct stripe_head_state s;
        struct r5dev *dev;
-       mdk_rdev_t *blocked_rdev = NULL;
        int prexor;
-       int dec_preread_active = 0;
-
-       memset(&s, 0, sizeof(s));
-       pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d check:%d "
-                "reconstruct:%d\n", (unsigned long long)sh->sector, sh->state,
-                atomic_read(&sh->count), sh->pd_idx, sh->check_state,
-                sh->reconstruct_state);
-
-       spin_lock(&sh->lock);
-       clear_bit(STRIPE_HANDLE, &sh->state);
-       clear_bit(STRIPE_DELAYED, &sh->state);
-
-       s.syncing = test_bit(STRIPE_SYNCING, &sh->state);
-       s.expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
-       s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
 
        /* Now to look around and see what can be done */
        rcu_read_lock();
+       spin_lock_irq(&conf->device_lock);
        for (i=disks; i--; ) {
                mdk_rdev_t *rdev;
 
@@ -3052,25 +3027,28 @@ static void handle_stripe5(struct stripe_head *sh)
                        set_bit(R5_Wantfill, &dev->flags);
 
                /* now count some things */
-               if (test_bit(R5_LOCKED, &dev->flags)) s.locked++;
-               if (test_bit(R5_UPTODATE, &dev->flags)) s.uptodate++;
-               if (test_bit(R5_Wantcompute, &dev->flags)) s.compute++;
+               if (test_bit(R5_LOCKED, &dev->flags))
+                       s->locked++;
+               if (test_bit(R5_UPTODATE, &dev->flags))
+                       s->uptodate++;
+               if (test_bit(R5_Wantcompute, &dev->flags))
+                       s->compute++;
 
                if (test_bit(R5_Wantfill, &dev->flags))
-                       s.to_fill++;
+                       s->to_fill++;
                else if (dev->toread)
-                       s.to_read++;
+                       s->to_read++;
                if (dev->towrite) {
-                       s.to_write++;
+                       s->to_write++;
                        if (!test_bit(R5_OVERWRITE, &dev->flags))
-                               s.non_overwrite++;
+                               s->non_overwrite++;
                }
                if (dev->written)
-                       s.written++;
+                       s->written++;
                rdev = rcu_dereference(conf->disks[i].rdev);
-               if (blocked_rdev == NULL &&
+               if (s->blocked_rdev == NULL &&
                    rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
-                       blocked_rdev = rdev;
+                       s->blocked_rdev = rdev;
                        atomic_inc(&rdev->nr_pending);
                }
                clear_bit(R5_Insync, &dev->flags);
@@ -3091,61 +3069,62 @@ static void handle_stripe5(struct stripe_head *sh)
                if (test_bit(R5_ReadError, &dev->flags))
                        clear_bit(R5_Insync, &dev->flags);
                if (!test_bit(R5_Insync, &dev->flags)) {
-                       s.failed++;
-                       s.failed_num = i;
+                       s->failed++;
+                       s->failed_num[0] = i;
                }
        }
+       spin_unlock_irq(&conf->device_lock);
        rcu_read_unlock();
 
-       if (unlikely(blocked_rdev)) {
-               if (s.syncing || s.expanding || s.expanded ||
-                   s.to_write || s.written) {
+       if (unlikely(s->blocked_rdev)) {
+               if (s->syncing || s->expanding || s->expanded ||
+                   s->to_write || s->written) {
                        set_bit(STRIPE_HANDLE, &sh->state);
-                       goto unlock;
+                       return 1;
                }
                /* There is nothing for the blocked_rdev to block */
-               rdev_dec_pending(blocked_rdev, conf->mddev);
-               blocked_rdev = NULL;
+               rdev_dec_pending(s->blocked_rdev, conf->mddev);
+               s->blocked_rdev = NULL;
        }
 
-       if (s.to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) {
-               set_bit(STRIPE_OP_BIOFILL, &s.ops_request);
+       if (s->to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) {
+               set_bit(STRIPE_OP_BIOFILL, &s->ops_request);
                set_bit(STRIPE_BIOFILL_RUN, &sh->state);
        }
 
        pr_debug("locked=%d uptodate=%d to_read=%d"
                " to_write=%d failed=%d failed_num=%d\n",
-               s.locked, s.uptodate, s.to_read, s.to_write,
-               s.failed, s.failed_num);
+               s->locked, s->uptodate, s->to_read, s->to_write,
+               s->failed, s->failed_num[0]);
        /* check if the array has lost two devices and, if so, some requests might
         * need to be failed
         */
-       if (s.failed > 1 && s.to_read+s.to_write+s.written)
-               handle_failed_stripe(conf, sh, &s, disks, &return_bi);
-       if (s.failed > 1 && s.syncing) {
+       if (s->failed > 1 && s->to_read+s->to_write+s->written)
+               handle_failed_stripe(conf, sh, s, disks, &s->return_bi);
+       if (s->failed > 1 && s->syncing) {
                md_done_sync(conf->mddev, STRIPE_SECTORS,0);
                clear_bit(STRIPE_SYNCING, &sh->state);
-               s.syncing = 0;
+               s->syncing = 0;
        }
 
        /* might be able to return some write requests if the parity block
         * is safe, or on a failed drive
         */
        dev = &sh->dev[sh->pd_idx];
-       if ( s.written &&
-            ((test_bit(R5_Insync, &dev->flags) &&
-              !test_bit(R5_LOCKED, &dev->flags) &&
-              test_bit(R5_UPTODATE, &dev->flags)) ||
-              (s.failed == 1 && s.failed_num == sh->pd_idx)))
-               handle_stripe_clean_event(conf, sh, disks, &return_bi);
+       if (s->written &&
+           ((test_bit(R5_Insync, &dev->flags) &&
+             !test_bit(R5_LOCKED, &dev->flags) &&
+             test_bit(R5_UPTODATE, &dev->flags)) ||
+            (s->failed == 1 && s->failed_num[0] == sh->pd_idx)))
+               handle_stripe_clean_event(conf, sh, disks, &s->return_bi);
 
        /* Now we might consider reading some blocks, either to check/generate
         * parity, or to satisfy requests
         * or to load a block that is being partially written.
         */
-       if (s.to_read || s.non_overwrite ||
-           (s.syncing && (s.uptodate + s.compute < disks)) || s.expanding)
-               handle_stripe_fill5(sh, &s, disks);
+       if (s->to_read || s->non_overwrite ||
+           (s->syncing && (s->uptodate + s->compute < disks)) || s->expanding)
+               handle_stripe_fill5(sh, s, disks);
 
        /* Now we check to see if any write operations have recently
         * completed
@@ -3170,12 +3149,12 @@ static void handle_stripe5(struct stripe_head *sh)
                                if (prexor)
                                        continue;
                                if (!test_bit(R5_Insync, &dev->flags) ||
-                                   (i == sh->pd_idx && s.failed == 0))
+                                   (i == sh->pd_idx && s->failed == 0))
                                        set_bit(STRIPE_INSYNC, &sh->state);
                        }
                }
                if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
-                       dec_preread_active = 1;
+                       s->dec_preread_active = 1;
        }
 
        /* Now to consider new write requests and what else, if anything
@@ -3184,8 +3163,8 @@ static void handle_stripe5(struct stripe_head *sh)
         * 2/ A 'check' operation is in flight, as it may clobber the parity
         *    block.
         */
-       if (s.to_write && !sh->reconstruct_state && !sh->check_state)
-               handle_stripe_dirtying5(conf, sh, &s, disks);
+       if (s->to_write && !sh->reconstruct_state && !sh->check_state)
+               handle_stripe_dirtying5(conf, sh, s, disks);
 
        /* maybe we need to check and possibly fix the parity for this stripe
         * Any reads will already have been scheduled, so we just see if enough
@@ -3193,12 +3172,13 @@ static void handle_stripe5(struct stripe_head *sh)
         * dependent operations are in flight.
         */
        if (sh->check_state ||
-           (s.syncing && s.locked == 0 &&
+           (s->syncing && s->locked == 0 &&
             !test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&
             !test_bit(STRIPE_INSYNC, &sh->state)))
-               handle_parity_checks5(conf, sh, &s, disks);
+               handle_parity_checks5(conf, sh, s, disks);
 
-       if (s.syncing && s.locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
+       if (s->syncing && s->locked == 0
+           && test_bit(STRIPE_INSYNC, &sh->state)) {
                md_done_sync(conf->mddev, STRIPE_SECTORS,1);
                clear_bit(STRIPE_SYNCING, &sh->state);
        }
@@ -3206,124 +3186,38 @@ static void handle_stripe5(struct stripe_head *sh)
        /* If the failed drive is just a ReadError, then we might need to progress
         * the repair/check process
         */
-       if (s.failed == 1 && !conf->mddev->ro &&
-           test_bit(R5_ReadError, &sh->dev[s.failed_num].flags)
-           && !test_bit(R5_LOCKED, &sh->dev[s.failed_num].flags)
-           && test_bit(R5_UPTODATE, &sh->dev[s.failed_num].flags)
+       if (s->failed == 1 && !conf->mddev->ro &&
+           test_bit(R5_ReadError, &sh->dev[s->failed_num[0]].flags)
+           && !test_bit(R5_LOCKED, &sh->dev[s->failed_num[0]].flags)
+           && test_bit(R5_UPTODATE, &sh->dev[s->failed_num[0]].flags)
                ) {
-               dev = &sh->dev[s.failed_num];
+               dev = &sh->dev[s->failed_num[0]];
                if (!test_bit(R5_ReWrite, &dev->flags)) {
                        set_bit(R5_Wantwrite, &dev->flags);
                        set_bit(R5_ReWrite, &dev->flags);
                        set_bit(R5_LOCKED, &dev->flags);
-                       s.locked++;
+                       s->locked++;
                } else {
                        /* let's read it back */
                        set_bit(R5_Wantread, &dev->flags);
                        set_bit(R5_LOCKED, &dev->flags);
-                       s.locked++;
-               }
-       }
-
-       /* Finish reconstruct operations initiated by the expansion process */
-       if (sh->reconstruct_state == reconstruct_state_result) {
-               struct stripe_head *sh2
-                       = get_active_stripe(conf, sh->sector, 1, 1, 1);
-               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
-                       /* sh cannot be written until sh2 has been read.
-                        * so arrange for sh to be delayed a little
-                        */
-                       set_bit(STRIPE_DELAYED, &sh->state);
-                       set_bit(STRIPE_HANDLE, &sh->state);
-                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
-                                             &sh2->state))
-                               atomic_inc(&conf->preread_active_stripes);
-                       release_stripe(sh2);
-                       goto unlock;
-               }
-               if (sh2)
-                       release_stripe(sh2);
-
-               sh->reconstruct_state = reconstruct_state_idle;
-               clear_bit(STRIPE_EXPANDING, &sh->state);
-               for (i = conf->raid_disks; i--; ) {
-                       set_bit(R5_Wantwrite, &sh->dev[i].flags);
-                       set_bit(R5_LOCKED, &sh->dev[i].flags);
-                       s.locked++;
+                       s->locked++;
                }
        }
-
-       if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) &&
-           !sh->reconstruct_state) {
-               /* Need to write out all blocks after computing parity */
-               sh->disks = conf->raid_disks;
-               stripe_set_idx(sh->sector, conf, 0, sh);
-               schedule_reconstruction(sh, &s, 1, 1);
-       } else if (s.expanded && !sh->reconstruct_state && s.locked == 0) {
-               clear_bit(STRIPE_EXPAND_READY, &sh->state);
-               atomic_dec(&conf->reshape_stripes);
-               wake_up(&conf->wait_for_overlap);
-               md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
-       }
-
-       if (s.expanding && s.locked == 0 &&
-           !test_bit(STRIPE_COMPUTE_RUN, &sh->state))
-               handle_stripe_expansion(conf, sh, NULL);
-
- unlock:
-       spin_unlock(&sh->lock);
-
-       /* wait for this device to become unblocked */
-       if (unlikely(blocked_rdev))
-               md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
-
-       if (s.ops_request)
-               raid_run_ops(sh, s.ops_request);
-
-       ops_run_io(sh, &s);
-
-       if (dec_preread_active) {
-               /* We delay this until after ops_run_io so that if make_request
-                * is waiting on a flush, it won't continue until the writes
-                * have actually been submitted.
-                */
-               atomic_dec(&conf->preread_active_stripes);
-               if (atomic_read(&conf->preread_active_stripes) <
-                   IO_THRESHOLD)
-                       md_wakeup_thread(conf->mddev->thread);
-       }
-       return_io(return_bi);
+       return 0;
 }
 
-static void handle_stripe6(struct stripe_head *sh)
+static int handle_stripe6(struct stripe_head *sh, struct stripe_head_state *s)
 {
        raid5_conf_t *conf = sh->raid_conf;
        int disks = sh->disks;
-       struct bio *return_bi = NULL;
        int i, pd_idx = sh->pd_idx, qd_idx = sh->qd_idx;
-       struct stripe_head_state s;
-       struct r6_state r6s;
        struct r5dev *dev, *pdev, *qdev;
-       mdk_rdev_t *blocked_rdev = NULL;
-       int dec_preread_active = 0;
 
-       pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
-               "pd_idx=%d, qd_idx=%d\n, check:%d, reconstruct:%d\n",
-              (unsigned long long)sh->sector, sh->state,
-              atomic_read(&sh->count), pd_idx, qd_idx,
-              sh->check_state, sh->reconstruct_state);
-       memset(&s, 0, sizeof(s));
-
-       spin_lock(&sh->lock);
-       clear_bit(STRIPE_HANDLE, &sh->state);
-       clear_bit(STRIPE_DELAYED, &sh->state);
-
-       s.syncing = test_bit(STRIPE_SYNCING, &sh->state);
-       s.expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
-       s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
        /* Now to look around and see what can be done */
 
        rcu_read_lock();
+       spin_lock_irq(&conf->device_lock);
        for (i=disks; i--; ) {
                mdk_rdev_t *rdev;
                dev = &sh->dev[i];
@@ -3340,28 +3234,30 @@ static void handle_stripe6(struct stripe_head *sh)
                        set_bit(R5_Wantfill, &dev->flags);
 
                /* now count some things */
-               if (test_bit(R5_LOCKED, &dev->flags)) s.locked++;
-               if (test_bit(R5_UPTODATE, &dev->flags)) s.uptodate++;
+               if (test_bit(R5_LOCKED, &dev->flags))
+                       s->locked++;
+               if (test_bit(R5_UPTODATE, &dev->flags))
+                       s->uptodate++;
                if (test_bit(R5_Wantcompute, &dev->flags)) {
-                       s.compute++;
-                       BUG_ON(s.compute > 2);
+                       s->compute++;
+                       BUG_ON(s->compute > 2);
                }
 
                if (test_bit(R5_Wantfill, &dev->flags)) {
-                       s.to_fill++;
+                       s->to_fill++;
                } else if (dev->toread)
-                       s.to_read++;
+                       s->to_read++;
                if (dev->towrite) {
-                       s.to_write++;
+                       s->to_write++;
                        if (!test_bit(R5_OVERWRITE, &dev->flags))
-                               s.non_overwrite++;
+                               s->non_overwrite++;
                }
                if (dev->written)
-                       s.written++;
+                       s->written++;
                rdev = rcu_dereference(conf->disks[i].rdev);
-               if (blocked_rdev == NULL &&
+               if (s->blocked_rdev == NULL &&
                    rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
-                       blocked_rdev = rdev;
+                       s->blocked_rdev = rdev;
                        atomic_inc(&rdev->nr_pending);
                }
                clear_bit(R5_Insync, &dev->flags);
@@ -3382,42 +3278,43 @@ static void handle_stripe6(struct stripe_head *sh)
                if (test_bit(R5_ReadError, &dev->flags))
                        clear_bit(R5_Insync, &dev->flags);
                if (!test_bit(R5_Insync, &dev->flags)) {
-                       if (s.failed < 2)
-                               r6s.failed_num[s.failed] = i;
-                       s.failed++;
+                       if (s->failed < 2)
+                               s->failed_num[s->failed] = i;
+                       s->failed++;
                }
        }
+       spin_unlock_irq(&conf->device_lock);
        rcu_read_unlock();
 
-       if (unlikely(blocked_rdev)) {
-               if (s.syncing || s.expanding || s.expanded ||
-                   s.to_write || s.written) {
+       if (unlikely(s->blocked_rdev)) {
+               if (s->syncing || s->expanding || s->expanded ||
+                   s->to_write || s->written) {
                        set_bit(STRIPE_HANDLE, &sh->state);
-                       goto unlock;
+                       return 1;
                }
                /* There is nothing for the blocked_rdev to block */
-               rdev_dec_pending(blocked_rdev, conf->mddev);
-               blocked_rdev = NULL;
+               rdev_dec_pending(s->blocked_rdev, conf->mddev);
+               s->blocked_rdev = NULL;
        }
 
-       if (s.to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) {
-               set_bit(STRIPE_OP_BIOFILL, &s.ops_request);
+       if (s->to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) {
+               set_bit(STRIPE_OP_BIOFILL, &s->ops_request);
                set_bit(STRIPE_BIOFILL_RUN, &sh->state);
        }
 
        pr_debug("locked=%d uptodate=%d to_read=%d"
               " to_write=%d failed=%d failed_num=%d,%d\n",
-              s.locked, s.uptodate, s.to_read, s.to_write, s.failed,
-              r6s.failed_num[0], r6s.failed_num[1]);
+              s->locked, s->uptodate, s->to_read, s->to_write, s->failed,
+              s->failed_num[0], s->failed_num[1]);
        /* check if the array has lost >2 devices and, if so, some requests
         * might need to be failed
         */
-       if (s.failed > 2 && s.to_read+s.to_write+s.written)
-               handle_failed_stripe(conf, sh, &s, disks, &return_bi);
-       if (s.failed > 2 && s.syncing) {
+       if (s->failed > 2 && s->to_read+s->to_write+s->written)
+               handle_failed_stripe(conf, sh, s, disks, &s->return_bi);
+       if (s->failed > 2 && s->syncing) {
                md_done_sync(conf->mddev, STRIPE_SECTORS,0);
                clear_bit(STRIPE_SYNCING, &sh->state);
-               s.syncing = 0;
+               s->syncing = 0;
        }
 
        /*
@@ -3425,28 +3322,28 @@ static void handle_stripe6(struct stripe_head *sh)
         * are safe, or on a failed drive
         */
        pdev = &sh->dev[pd_idx];
-       r6s.p_failed = (s.failed >= 1 && r6s.failed_num[0] == pd_idx)
-               || (s.failed >= 2 && r6s.failed_num[1] == pd_idx);
+       s->p_failed = (s->failed >= 1 && s->failed_num[0] == pd_idx)
+               || (s->failed >= 2 && s->failed_num[1] == pd_idx);
        qdev = &sh->dev[qd_idx];
-       r6s.q_failed = (s.failed >= 1 && r6s.failed_num[0] == qd_idx)
-               || (s.failed >= 2 && r6s.failed_num[1] == qd_idx);
+       s->q_failed = (s->failed >= 1 && s->failed_num[0] == qd_idx)
+               || (s->failed >= 2 && s->failed_num[1] == qd_idx);
 
-       if ( s.written &&
-            ( r6s.p_failed || ((test_bit(R5_Insync, &pdev->flags)
+       if (s->written &&
+           (s->p_failed || ((test_bit(R5_Insync, &pdev->flags)
                             && !test_bit(R5_LOCKED, &pdev->flags)
                             && test_bit(R5_UPTODATE, &pdev->flags)))) &&
-            ( r6s.q_failed || ((test_bit(R5_Insync, &qdev->flags)
+           (s->q_failed || ((test_bit(R5_Insync, &qdev->flags)
                             && !test_bit(R5_LOCKED, &qdev->flags)
                             && test_bit(R5_UPTODATE, &qdev->flags)))))
-               handle_stripe_clean_event(conf, sh, disks, &return_bi);
+               handle_stripe_clean_event(conf, sh, disks, &s->return_bi);
 
        /* Now we might consider reading some blocks, either to check/generate
         * parity, or to satisfy requests
         * or to load a block that is being partially written.
         */
-       if (s.to_read || s.non_overwrite || (s.to_write && s.failed) ||
-           (s.syncing && (s.uptodate + s.compute < disks)) || s.expanding)
-               handle_stripe_fill6(sh, &s, &r6s, disks);
+       if (s->to_read || s->non_overwrite || (s->to_write && s->failed) ||
+           (s->syncing && (s->uptodate + s->compute < disks)) || s->expanding)
+               handle_stripe_fill6(sh, s, disks);
 
        /* Now we check to see if any write operations have recently
         * completed
@@ -3469,12 +3366,12 @@ static void handle_stripe6(struct stripe_head *sh)
                                set_bit(R5_Wantwrite, &dev->flags);
                                if (!test_bit(R5_Insync, &dev->flags) ||
                                    ((i == sh->pd_idx || i == qd_idx) &&
-                                     s.failed == 0))
+                                     s->failed == 0))
                                        set_bit(STRIPE_INSYNC, &sh->state);
                        }
                }
                if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
-                       dec_preread_active = 1;
+                       s->dec_preread_active = 1;
        }
 
        /* Now to consider new write requests and what else, if anything
@@ -3483,8 +3380,8 @@ static void handle_stripe6(struct stripe_head *sh)
         * 2/ A 'check' operation is in flight, as it may clobber the parity
         *    block.
         */
-       if (s.to_write && !sh->reconstruct_state && !sh->check_state)
-               handle_stripe_dirtying6(conf, sh, &s, &r6s, disks);
+       if (s->to_write && !sh->reconstruct_state && !sh->check_state)
+               handle_stripe_dirtying6(conf, sh, s, disks);
 
        /* maybe we need to check and possibly fix the parity for this stripe
         * Any reads will already have been scheduled, so we just see if enough
@@ -3492,12 +3389,13 @@ static void handle_stripe6(struct stripe_head *sh)
         * dependent operations are in flight.
         */
        if (sh->check_state ||
-           (s.syncing && s.locked == 0 &&
+           (s->syncing && s->locked == 0 &&
             !test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&
             !test_bit(STRIPE_INSYNC, &sh->state)))
-               handle_parity_checks6(conf, sh, &s, &r6s, disks);
+               handle_parity_checks6(conf, sh, s, disks);
 
-       if (s.syncing && s.locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
+       if (s->syncing && s->locked == 0
+           && test_bit(STRIPE_INSYNC, &sh->state)) {
                md_done_sync(conf->mddev, STRIPE_SECTORS,1);
                clear_bit(STRIPE_SYNCING, &sh->state);
        }
@@ -3505,9 +3403,9 @@ static void handle_stripe6(struct stripe_head *sh)
        /* If the failed drives are just a ReadError, then we might need
         * to progress the repair/check process
         */
-       if (s.failed <= 2 && !conf->mddev->ro)
-               for (i = 0; i < s.failed; i++) {
-                       dev = &sh->dev[r6s.failed_num[i]];
+       if (s->failed <= 2 && !conf->mddev->ro)
+               for (i = 0; i < s->failed; i++) {
+                       dev = &sh->dev[s->failed_num[i]];
                        if (test_bit(R5_ReadError, &dev->flags)
                            && !test_bit(R5_LOCKED, &dev->flags)
                            && test_bit(R5_UPTODATE, &dev->flags)
@@ -3516,18 +3414,76 @@ static void handle_stripe6(struct stripe_head *sh)
                                        set_bit(R5_Wantwrite, &dev->flags);
                                        set_bit(R5_ReWrite, &dev->flags);
                                        set_bit(R5_LOCKED, &dev->flags);
-                                       s.locked++;
+                                       s->locked++;
                                } else {
                                        /* let's read it back */
                                        set_bit(R5_Wantread, &dev->flags);
                                        set_bit(R5_LOCKED, &dev->flags);
-                                       s.locked++;
+                                       s->locked++;
                                }
                        }
                }
+       return 0;
+}
+
+static void handle_stripe(struct stripe_head *sh)
+{
+       struct stripe_head_state s;
+       int done;
+       int i;
+       raid5_conf_t *conf = sh->raid_conf;
+
+       clear_bit(STRIPE_HANDLE, &sh->state);
+       if (test_and_set_bit(STRIPE_ACTIVE, &sh->state)) {
+               /* already being handled, ensure it gets handled
+                * again when current action finishes */
+               set_bit(STRIPE_HANDLE, &sh->state);
+               return;
+       }
+
+       if (test_and_clear_bit(STRIPE_SYNC_REQUESTED, &sh->state)) {
+               set_bit(STRIPE_SYNCING, &sh->state);
+               clear_bit(STRIPE_INSYNC, &sh->state);
+       }
+       clear_bit(STRIPE_DELAYED, &sh->state);
+
+       pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
+               "pd_idx=%d, qd_idx=%d\n, check:%d, reconstruct:%d\n",
+              (unsigned long long)sh->sector, sh->state,
+              atomic_read(&sh->count), sh->pd_idx, sh->qd_idx,
+              sh->check_state, sh->reconstruct_state);
+       memset(&s, 0, sizeof(s));
 
+       s.syncing = test_bit(STRIPE_SYNCING, &sh->state);
+       s.expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+       s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
+
+       if (conf->level == 6)
+               done = handle_stripe6(sh, &s);
+       else
+               done = handle_stripe5(sh, &s);
+
+       if (done)
+               goto finish;
        /* Finish reconstruct operations initiated by the expansion process */
        if (sh->reconstruct_state == reconstruct_state_result) {
+               struct stripe_head *sh_src
+                       = get_active_stripe(conf, sh->sector, 1, 1, 1);
+               if (sh_src && test_bit(STRIPE_EXPAND_SOURCE, &sh_src->state)) {
+                       /* sh cannot be written until sh_src has been read.
+                        * so arrange for sh to be delayed a little
+                        */
+                       set_bit(STRIPE_DELAYED, &sh->state);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
+                                             &sh_src->state))
+                               atomic_inc(&conf->preread_active_stripes);
+                       release_stripe(sh_src);
+                       goto finish;
+               }
+               if (sh_src)
+                       release_stripe(sh_src);
+
                sh->reconstruct_state = reconstruct_state_idle;
                clear_bit(STRIPE_EXPANDING, &sh->state);
                for (i = conf->raid_disks; i--; ) {
@@ -3539,24 +3495,7 @@ static void handle_stripe6(struct stripe_head *sh)
 
        if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) &&
            !sh->reconstruct_state) {
-               struct stripe_head *sh2
-                       = get_active_stripe(conf, sh->sector, 1, 1, 1);
-               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
-                       /* sh cannot be written until sh2 has been read.
-                        * so arrange for sh to be delayed a little
-                        */
-                       set_bit(STRIPE_DELAYED, &sh->state);
-                       set_bit(STRIPE_HANDLE, &sh->state);
-                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
-                                             &sh2->state))
-                               atomic_inc(&conf->preread_active_stripes);
-                       release_stripe(sh2);
-                       goto unlock;
-               }
-               if (sh2)
-                       release_stripe(sh2);
-
-               /* Need to write out all blocks after computing P&Q */
+               /* Need to write out all blocks after computing parity */
                sh->disks = conf->raid_disks;
                stripe_set_idx(sh->sector, conf, 0, sh);
                schedule_reconstruction(sh, &s, 1, 1);
@@ -3569,14 +3508,12 @@ static void handle_stripe6(struct stripe_head *sh)
 
        if (s.expanding && s.locked == 0 &&
            !test_bit(STRIPE_COMPUTE_RUN, &sh->state))
-               handle_stripe_expansion(conf, sh, &r6s);
-
- unlock:
-       spin_unlock(&sh->lock);
+               handle_stripe_expansion(conf, sh);
 
+finish:
        /* wait for this device to become unblocked */
-       if (unlikely(blocked_rdev))
-               md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+       if (unlikely(s.blocked_rdev))
+               md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev);
 
        if (s.ops_request)
                raid_run_ops(sh, s.ops_request);
@@ -3584,7 +3521,7 @@ static void handle_stripe6(struct stripe_head *sh)
        ops_run_io(sh, &s);
 
 
-       if (dec_preread_active) {
+       if (s.dec_preread_active) {
                /* We delay this until after ops_run_io so that if make_request
                 * is waiting on a flush, it won't continue until the writes
                 * have actually been submitted.
@@ -3595,15 +3532,9 @@ static void handle_stripe6(struct stripe_head *sh)
                        md_wakeup_thread(conf->mddev->thread);
        }
 
-       return_io(return_bi);
-}
+       return_io(s.return_bi);
 
-static void handle_stripe(struct stripe_head *sh)
-{
-       if (sh->raid_conf->level == 6)
-               handle_stripe6(sh);
-       else
-               handle_stripe5(sh);
+       clear_bit(STRIPE_ACTIVE, &sh->state);
 }
 
 static void raid5_activate_delayed(raid5_conf_t *conf)
@@ -4016,7 +3947,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
                                }
                        }
 
-                       if (bio_data_dir(bi) == WRITE &&
+                       if (rw == WRITE &&
                            logical_sector >= mddev->suspend_lo &&
                            logical_sector < mddev->suspend_hi) {
                                release_stripe(sh);
@@ -4034,7 +3965,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
                        }
 
                        if (test_bit(STRIPE_EXPANDING, &sh->state) ||
-                           !add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) {
+                           !add_stripe_bio(sh, bi, dd_idx, rw)) {
                                /* Stripe is busy expanding or
                                 * add failed due to overlap.  Flush everything
                                 * and wait a while
@@ -4375,10 +4306,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
 
        bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
 
-       spin_lock(&sh->lock);
-       set_bit(STRIPE_SYNCING, &sh->state);
-       clear_bit(STRIPE_INSYNC, &sh->state);
-       spin_unlock(&sh->lock);
+       set_bit(STRIPE_SYNC_REQUESTED, &sh->state);
 
        handle_stripe(sh);
        release_stripe(sh);