Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 19 Sep 2017 15:39:32 +0000 (08:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 19 Sep 2017 15:39:32 +0000 (08:39 -0700)
Pull MD fixes from Shaohua Li:
 "Two small patches to fix long-lived raid5 stripe batch bugs, one from
  Dennis and the other from me"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md:
  md/raid5: preserve STRIPE_ON_UNPLUG_LIST in break_stripe_batch_list
  md/raid5: fix a race condition in stripe batch

drivers/md/raid5.c

index 4188a488114814aadf7df7b4c2ba07240b8e0408..076409455b603582f589ea8fcc68173d421ca33a 100644 (file)
@@ -811,6 +811,14 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh
                        spin_unlock(&head->batch_head->batch_lock);
                        goto unlock_out;
                }
+               /*
+                * We must assign batch_head of this stripe within the
+                * batch_lock, otherwise clear_batch_ready of batch head
+                * stripe could clear BATCH_READY bit of this stripe and
+                * this stripe->batch_head doesn't get assigned, which
+                * could confuse clear_batch_ready for this stripe
+                */
+               sh->batch_head = head->batch_head;
 
                /*
                 * at this point, head's BATCH_READY could be cleared, but we
@@ -818,8 +826,6 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh
                 */
                list_add(&sh->batch_list, &head->batch_list);
                spin_unlock(&head->batch_head->batch_lock);
-
-               sh->batch_head = head->batch_head;
        } else {
                head->batch_head = head;
                sh->batch_head = head->batch_head;
@@ -4599,7 +4605,8 @@ static void break_stripe_batch_list(struct stripe_head *head_sh,
 
                set_mask_bits(&sh->state, ~(STRIPE_EXPAND_SYNC_FLAGS |
                                            (1 << STRIPE_PREREAD_ACTIVE) |
-                                           (1 << STRIPE_DEGRADED)),
+                                           (1 << STRIPE_DEGRADED) |
+                                           (1 << STRIPE_ON_UNPLUG_LIST)),
                              head_sh->state & (1 << STRIPE_INSYNC));
 
                sh->check_state = head_sh->check_state;