Merge tag 'md/3.13' of git://neil.brown.name/md
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Nov 2013 21:05:25 +0000 (13:05 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Nov 2013 21:05:25 +0000 (13:05 -0800)
Pull md update from Neil Brown:
 "Mostly optimisations and obscure bug fixes.
   - raid5 gets less lock contention
   - raid1 gets less contention between normal-io and resync-io during
     resync"

* tag 'md/3.13' of git://neil.brown.name/md:
  md/raid5: Use conf->device_lock protect changing of multi-thread resources.
  md/raid5: Before freeing old multi-thread worker, it should flush them.
  md/raid5: For stripe with R5_ReadNoMerge, we replace REQ_FLUSH with REQ_NOMERGE.
  UAPI: include <asm/byteorder.h> in linux/raid/md_p.h
  raid1: Rewrite the implementation of iobarrier.
  raid1: Add some macros to make code clearly.
  raid1: Replace raise_barrier/lower_barrier with freeze_array/unfreeze_array when reconfiguring the array.
  raid1: Add a field array_frozen to indicate whether raid in freeze state.
  md: Convert use of typedef ctl_table to struct ctl_table
  md/raid5: avoid deadlock when raid5 array has unack badblocks during md_stop_writes.
  md: use MD_RECOVERY_INTR instead of kthread_should_stop in resync thread.
  md: fix some places where mddev_lock return value is not checked.
  raid5: Retry R5_ReadNoMerge flag when hit a read error.
  raid5: relieve lock contention in get_active_stripe()
  raid5: relieve lock contention in get_active_stripe()
  wait: add wait_event_cmd()
  md/raid5.c: add proper locking to error path of raid5_start_reshape.
  md: fix calculation of stacking limits on level change.
  raid5: Use slow_path to release stripe when mddev->thread is null

1  2 
drivers/md/md.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid5.h

diff --cc drivers/md/md.c
Simple merge
Simple merge
Simple merge
index 7f0e17a27aebcd3b448dca34290ab1c735c89eb1,c7db410190c431ded7d3863459bd526508063e71..47da0af6322be1bd7930f902c96c57875799a358
@@@ -287,14 -320,77 +320,63 @@@ static void do_release_stripe(struct r5
        }
  }
  
- static void __release_stripe(struct r5conf *conf, struct stripe_head *sh)
+ static void __release_stripe(struct r5conf *conf, struct stripe_head *sh,
+                            struct list_head *temp_inactive_list)
  {
        if (atomic_dec_and_test(&sh->count))
-               do_release_stripe(conf, sh);
+               do_release_stripe(conf, sh, temp_inactive_list);
+ }
+ /*
+  * @hash could be NR_STRIPE_HASH_LOCKS, then we have a list of inactive_list
+  *
+  * Be careful: Only one task can add/delete stripes from temp_inactive_list at
+  * given time. Adding stripes only takes device lock, while deleting stripes
+  * only takes hash lock.
+  */
+ static void release_inactive_stripe_list(struct r5conf *conf,
+                                        struct list_head *temp_inactive_list,
+                                        int hash)
+ {
+       int size;
+       bool do_wakeup = false;
+       unsigned long flags;
+       if (hash == NR_STRIPE_HASH_LOCKS) {
+               size = NR_STRIPE_HASH_LOCKS;
+               hash = NR_STRIPE_HASH_LOCKS - 1;
+       } else
+               size = 1;
+       while (size) {
+               struct list_head *list = &temp_inactive_list[size - 1];
+               /*
+                * We don't hold any lock here yet, get_active_stripe() might
+                * remove stripes from the list
+                */
+               if (!list_empty_careful(list)) {
+                       spin_lock_irqsave(conf->hash_locks + hash, flags);
+                       if (list_empty(conf->inactive_list + hash) &&
+                           !list_empty(list))
+                               atomic_dec(&conf->empty_inactive_list_nr);
+                       list_splice_tail_init(list, conf->inactive_list + hash);
+                       do_wakeup = true;
+                       spin_unlock_irqrestore(conf->hash_locks + hash, flags);
+               }
+               size--;
+               hash--;
+       }
+       if (do_wakeup) {
+               wake_up(&conf->wait_for_stripe);
+               if (conf->retry_read_aligned)
+                       md_wakeup_thread(conf->mddev->thread);
+       }
  }
  
 -static struct llist_node *llist_reverse_order(struct llist_node *head)
 -{
 -      struct llist_node *new_head = NULL;
 -
 -      while (head) {
 -              struct llist_node *tmp = head;
 -              head = head->next;
 -              tmp->next = new_head;
 -              new_head = tmp;
 -      }
 -
 -      return new_head;
 -}
 -
  /* should hold conf->device_lock already */
- static int release_stripe_list(struct r5conf *conf)
+ static int release_stripe_list(struct r5conf *conf,
+                              struct list_head *temp_inactive_list)
  {
        struct stripe_head *sh;
        int count = 0;
Simple merge