srcu: Push srcu_advance_batches() fastpath into common case
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Fri, 10 Mar 2017 00:16:42 +0000 (16:16 -0800)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Tue, 18 Apr 2017 18:38:19 +0000 (11:38 -0700)
This commit simplifies the SRCU state machine by pushing the
srcu_advance_batches() idle-SRCU fastpath into the common case.  This is
done by giving srcu_reschedule() a delay parameter, which is zero in
the call from srcu_advance_batches().

This commit is a step towards numbering callbacks in order to
efficiently handle per-CPU callback lists.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
kernel/rcu/srcu.c

index 7e7ecaa50dc5ec2a037fb5c674b8ad9f1cd9317b..821ecda873f2232feae0340f69086832b41787fa 100644 (file)
@@ -399,8 +399,7 @@ void call_srcu(struct srcu_struct *sp, struct rcu_head *head,
 }
 EXPORT_SYMBOL_GPL(call_srcu);
 
-static void srcu_advance_batches(struct srcu_struct *sp, int trycount);
-static void srcu_reschedule(struct srcu_struct *sp);
+static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay);
 
 /*
  * Helper function for synchronize_srcu() and synchronize_srcu_expedited().
@@ -409,7 +408,6 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount)
 {
        struct rcu_synchronize rcu;
        struct rcu_head *head = &rcu.head;
-       bool done = false;
 
        RCU_LOCKDEP_WARN(lock_is_held(&sp->dep_map) ||
                         lock_is_held(&rcu_bh_lock_map) ||
@@ -431,25 +429,15 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount)
                sp->running = true;
                rcu_batch_queue(&sp->batch_check0, head);
                spin_unlock_irq(&sp->queue_lock);
-
-               srcu_advance_batches(sp, trycount);
-               if (!rcu_batch_empty(&sp->batch_done)) {
-                       BUG_ON(sp->batch_done.head != head);
-                       rcu_batch_dequeue(&sp->batch_done);
-                       done = true;
-               }
                /* give the processing owner to work_struct */
-               srcu_reschedule(sp);
+               srcu_reschedule(sp, 0);
        } else {
                rcu_batch_queue(&sp->batch_queue, head);
                spin_unlock_irq(&sp->queue_lock);
        }
 
-       if (!done) {
-               wait_for_completion(&rcu.completion);
-               smp_mb(); /* Caller's later accesses after GP. */
-       }
-
+       wait_for_completion(&rcu.completion);
+       smp_mb(); /* Caller's later accesses after GP. */
 }
 
 /**
@@ -639,7 +627,7 @@ static void srcu_invoke_callbacks(struct srcu_struct *sp)
  * Finished one round of SRCU grace period.  Start another if there are
  * more SRCU callbacks queued, otherwise put SRCU into not-running state.
  */
-static void srcu_reschedule(struct srcu_struct *sp)
+static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay)
 {
        bool pending = true;
 
@@ -653,8 +641,7 @@ static void srcu_reschedule(struct srcu_struct *sp)
        }
 
        if (pending)
-               queue_delayed_work(system_power_efficient_wq,
-                                  &sp->work, SRCU_INTERVAL);
+               queue_delayed_work(system_power_efficient_wq, &sp->work, delay);
 }
 
 /*
@@ -669,6 +656,6 @@ void process_srcu(struct work_struct *work)
        srcu_collect_new(sp);
        srcu_advance_batches(sp, 1);
        srcu_invoke_callbacks(sp);
-       srcu_reschedule(sp);
+       srcu_reschedule(sp, SRCU_INTERVAL);
 }
 EXPORT_SYMBOL_GPL(process_srcu);