Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux.git] / drivers / md / raid5.c
index 16f5c21963db5391ed25fd1e185ab8399f353e74..25247a8529124f7cc93eda0db7033655d52f2ef7 100644 (file)
@@ -679,14 +679,9 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
                                init_stripe(sh, sector, previous);
                                atomic_inc(&sh->count);
                        }
-               } else {
+               } else if (!atomic_inc_not_zero(&sh->count)) {
                        spin_lock(&conf->device_lock);
-                       if (atomic_read(&sh->count)) {
-                               BUG_ON(!list_empty(&sh->lru)
-                                   && !test_bit(STRIPE_EXPANDING, &sh->state)
-                                   && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)
-                                       );
-                       } else {
+                       if (!atomic_read(&sh->count)) {
                                if (!test_bit(STRIPE_HANDLE, &sh->state))
                                        atomic_inc(&conf->active_stripes);
                                BUG_ON(list_empty(&sh->lru) &&
@@ -4552,6 +4547,8 @@ static void make_request(struct mddev *mddev, struct bio * bi)
        struct stripe_head *sh;
        const int rw = bio_data_dir(bi);
        int remaining;
+       DEFINE_WAIT(w);
+       bool do_prepare;
 
        if (unlikely(bi->bi_rw & REQ_FLUSH)) {
                md_flush_request(mddev, bi);
@@ -4575,15 +4572,18 @@ static void make_request(struct mddev *mddev, struct bio * bi)
        bi->bi_next = NULL;
        bi->bi_phys_segments = 1;       /* over-loaded to count active stripes */
 
+       prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
        for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
-               DEFINE_WAIT(w);
                int previous;
                int seq;
 
+               do_prepare = false;
        retry:
                seq = read_seqcount_begin(&conf->gen_lock);
                previous = 0;
-               prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
+               if (do_prepare)
+                       prepare_to_wait(&conf->wait_for_overlap, &w,
+                               TASK_UNINTERRUPTIBLE);
                if (unlikely(conf->reshape_progress != MaxSector)) {
                        /* spinlock is needed as reshape_progress may be
                         * 64bit on a 32bit platform, and so it might be
@@ -4604,6 +4604,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                                    : logical_sector >= conf->reshape_safe) {
                                        spin_unlock_irq(&conf->device_lock);
                                        schedule();
+                                       do_prepare = true;
                                        goto retry;
                                }
                        }
@@ -4640,6 +4641,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                                if (must_retry) {
                                        release_stripe(sh);
                                        schedule();
+                                       do_prepare = true;
                                        goto retry;
                                }
                        }
@@ -4663,8 +4665,10 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                                prepare_to_wait(&conf->wait_for_overlap,
                                                &w, TASK_INTERRUPTIBLE);
                                if (logical_sector >= mddev->suspend_lo &&
-                                   logical_sector < mddev->suspend_hi)
+                                   logical_sector < mddev->suspend_hi) {
                                        schedule();
+                                       do_prepare = true;
+                               }
                                goto retry;
                        }
 
@@ -4677,9 +4681,9 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                                md_wakeup_thread(mddev->thread);
                                release_stripe(sh);
                                schedule();
+                               do_prepare = true;
                                goto retry;
                        }
-                       finish_wait(&conf->wait_for_overlap, &w);
                        set_bit(STRIPE_HANDLE, &sh->state);
                        clear_bit(STRIPE_DELAYED, &sh->state);
                        if ((bi->bi_rw & REQ_SYNC) &&
@@ -4689,10 +4693,10 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                } else {
                        /* cannot get stripe for read-ahead, just give-up */
                        clear_bit(BIO_UPTODATE, &bi->bi_flags);
-                       finish_wait(&conf->wait_for_overlap, &w);
                        break;
                }
        }
+       finish_wait(&conf->wait_for_overlap, &w);
 
        remaining = raid5_dec_bi_active_stripes(bi);
        if (remaining == 0) {