rcu: Make rcu_migrate_callbacks wake GP kthread when needed
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Sun, 22 Apr 2018 15:49:24 +0000 (08:49 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Tue, 15 May 2018 17:29:51 +0000 (10:29 -0700)
The rcu_migrate_callbacks() function invokes rcu_advance_cbs()
twice, ignoring the return value.  This is OK at pressent because of
failsafe code that does the wakeup when needed.  However, this failsafe
code acquires the root rcu_node structure's lock frequently, while
rcu_migrate_callbacks() does so only once per CPU-offline operation.

This commit therefore makes rcu_migrate_callbacks()
wake up the RCU GP kthread when either call to rcu_advance_cbs()
returns true, thus removing need for the failsafe code.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Nicholas Piggin <npiggin@gmail.com>
kernel/rcu/tree.c

index 6ef1f2b..f75eb51 100644 (file)
@@ -3876,6 +3876,7 @@ static void rcu_migrate_callbacks(int cpu, struct rcu_state *rsp)
        struct rcu_data *my_rdp;
        struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp_root = rcu_get_root(rdp->rsp);
+       bool needwake;
 
        if (rcu_is_nocb_cpu(cpu) || rcu_segcblist_empty(&rdp->cblist))
                return;  /* No callbacks to migrate. */
@@ -3887,12 +3888,15 @@ static void rcu_migrate_callbacks(int cpu, struct rcu_state *rsp)
                return;
        }
        raw_spin_lock_rcu_node(rnp_root); /* irqs already disabled. */
-       rcu_advance_cbs(rsp, rnp_root, rdp); /* Leverage recent GPs. */
-       rcu_advance_cbs(rsp, rnp_root, my_rdp); /* Assign GP to pending CBs. */
+       /* Leverage recent GPs and set GP for new callbacks. */
+       needwake = rcu_advance_cbs(rsp, rnp_root, rdp) ||
+                  rcu_advance_cbs(rsp, rnp_root, my_rdp);
        rcu_segcblist_merge(&my_rdp->cblist, &rdp->cblist);
        WARN_ON_ONCE(rcu_segcblist_empty(&my_rdp->cblist) !=
                     !rcu_segcblist_n_cbs(&my_rdp->cblist));
        raw_spin_unlock_irqrestore_rcu_node(rnp_root, flags);
+       if (needwake)
+               rcu_gp_kthread_wake(rsp);
        WARN_ONCE(rcu_segcblist_n_cbs(&rdp->cblist) != 0 ||
                  !rcu_segcblist_empty(&rdp->cblist),
                  "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, 1stCB=%p\n",