rcu: Convert rcutree to hotplug state machine
authorThomas Gleixner <tglx@linutronix.de>
Wed, 13 Jul 2016 17:17:03 +0000 (17:17 +0000)
committerIngo Molnar <mingo@kernel.org>
Fri, 15 Jul 2016 08:41:44 +0000 (10:41 +0200)
Straight forward conversion to the state machine. Though the question arises
whether this needs really all these state transitions to work.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: rt@linutronix.de
Link: http://lkml.kernel.org/r/20160713153337.982013161@linutronix.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
include/linux/cpuhotplug.h
include/linux/rcutiny.h
include/linux/rcutree.h
kernel/cpu.c
kernel/rcu/tree.c

index 544b5563720eca432c10fd5c3e100c08bae00291..201a2e23bc49a0cee56c2db65f728840db6ab004 100644 (file)
@@ -20,11 +20,13 @@ enum cpuhp_state {
        CPUHP_X2APIC_PREPARE,
        CPUHP_SMPCFD_PREPARE,
        CPUHP_TIMERS_DEAD,
+       CPUHP_RCUTREE_PREP,
        CPUHP_NOTIFY_PREPARE,
        CPUHP_BRINGUP_CPU,
        CPUHP_AP_IDLE_DEAD,
        CPUHP_AP_OFFLINE,
        CPUHP_AP_SCHED_STARTING,
+       CPUHP_AP_RCUTREE_DYING,
        CPUHP_AP_IRQ_GIC_STARTING,
        CPUHP_AP_IRQ_GICV3_STARTING,
        CPUHP_AP_IRQ_HIP04_STARTING,
@@ -80,6 +82,7 @@ enum cpuhp_state {
        CPUHP_AP_PERF_ARM_CCI_ONLINE,
        CPUHP_AP_PERF_ARM_CCN_ONLINE,
        CPUHP_AP_WORKQUEUE_ONLINE,
+       CPUHP_AP_RCUTREE_ONLINE,
        CPUHP_AP_NOTIFY_ONLINE,
        CPUHP_AP_ONLINE_DYN,
        CPUHP_AP_ONLINE_DYN_END         = CPUHP_AP_ONLINE_DYN + 30,
index 93aea75029fbd7795e99ffcf77d781ed122f1cba..ac81e4063b407a6525931ff78cdf51544547646e 100644 (file)
@@ -243,4 +243,11 @@ static inline void rcu_all_qs(void)
        barrier(); /* Avoid RCU read-side critical sections leaking across. */
 }
 
+/* RCUtree hotplug events */
+#define rcutree_prepare_cpu      NULL
+#define rcutree_online_cpu       NULL
+#define rcutree_offline_cpu      NULL
+#define rcutree_dead_cpu         NULL
+#define rcutree_dying_cpu        NULL
+
 #endif /* __LINUX_RCUTINY_H */
index 5043cb823fb273b48a24c5366e800ee704000355..63a4e4cf40a54315705cec804c8f065bdcf2cdbb 100644 (file)
@@ -111,4 +111,11 @@ bool rcu_is_watching(void);
 
 void rcu_all_qs(void);
 
+/* RCUtree hotplug events */
+int rcutree_prepare_cpu(unsigned int cpu);
+int rcutree_online_cpu(unsigned int cpu);
+int rcutree_offline_cpu(unsigned int cpu);
+int rcutree_dead_cpu(unsigned int cpu);
+int rcutree_dying_cpu(unsigned int cpu);
+
 #endif /* __LINUX_RCUTREE_H */
index 008e2fd40cb18cafa7eeb11a1a75f1d3e73eef26..f24f45915b54c50b8f0ac84231d370983fd9b9b3 100644 (file)
@@ -1205,6 +1205,11 @@ static struct cpuhp_step cpuhp_bp_states[] = {
                .startup = NULL,
                .teardown = timers_dead_cpu,
        },
+       [CPUHP_RCUTREE_PREP] = {
+               .name = "RCU-tree prepare",
+               .startup = rcutree_prepare_cpu,
+               .teardown = rcutree_dead_cpu,
+       },
        /*
         * Preparatory and dead notifiers. Will be replaced once the notifiers
         * are converted to states.
@@ -1263,6 +1268,10 @@ static struct cpuhp_step cpuhp_ap_states[] = {
                .startup                = sched_cpu_starting,
                .teardown               = sched_cpu_dying,
        },
+       [CPUHP_AP_RCUTREE_DYING] = {
+               .startup = NULL,
+               .teardown = rcutree_dying_cpu,
+       },
        /*
         * Low level startup/teardown notifiers. Run with interrupts
         * disabled. Will be removed once the notifiers are converted to
@@ -1296,6 +1305,11 @@ static struct cpuhp_step cpuhp_ap_states[] = {
                .startup = workqueue_online_cpu,
                .teardown = workqueue_offline_cpu,
        },
+       [CPUHP_AP_RCUTREE_ONLINE] = {
+               .name = "RCU-tree online",
+               .startup = rcutree_online_cpu,
+               .teardown = rcutree_offline_cpu,
+       },
 
        /*
         * Online/down_prepare notifiers. Will be removed once the notifiers
index f433959e9322c20c9c93aa7d502d1deb5b0011c2..5d80925e7fc8638fda26465273dcf78fbc015a0a 100644 (file)
@@ -1073,11 +1073,11 @@ EXPORT_SYMBOL_GPL(rcu_is_watching);
  * offline to continue to use RCU for one jiffy after marking itself
  * offline in the cpu_online_mask.  This leniency is necessary given the
  * non-atomic nature of the online and offline processing, for example,
- * the fact that a CPU enters the scheduler after completing the CPU_DYING
- * notifiers.
+ * the fact that a CPU enters the scheduler after completing the teardown
+ * of the CPU.
  *
- * This is also why RCU internally marks CPUs online during the
- * CPU_UP_PREPARE phase and offline during the CPU_DEAD phase.
+ * This is also why RCU internally marks CPUs online during in the
+ * preparation phase and offline after the CPU has been taken down.
  *
  * Disable checking if in an NMI handler because we cannot safely report
  * errors from NMI handlers anyway.
@@ -3806,12 +3806,58 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
 }
 
-static void rcu_prepare_cpu(int cpu)
+int rcutree_prepare_cpu(unsigned int cpu)
 {
        struct rcu_state *rsp;
 
        for_each_rcu_flavor(rsp)
                rcu_init_percpu_data(cpu, rsp);
+
+       rcu_prepare_kthreads(cpu);
+       rcu_spawn_all_nocb_kthreads(cpu);
+
+       return 0;
+}
+
+static void rcutree_affinity_setting(unsigned int cpu, int outgoing)
+{
+       struct rcu_data *rdp = per_cpu_ptr(rcu_state_p->rda, cpu);
+
+       rcu_boost_kthread_setaffinity(rdp->mynode, outgoing);
+}
+
+int rcutree_online_cpu(unsigned int cpu)
+{
+       sync_sched_exp_online_cleanup(cpu);
+       rcutree_affinity_setting(cpu, -1);
+       return 0;
+}
+
+int rcutree_offline_cpu(unsigned int cpu)
+{
+       rcutree_affinity_setting(cpu, cpu);
+       return 0;
+}
+
+
+int rcutree_dying_cpu(unsigned int cpu)
+{
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp)
+               rcu_cleanup_dying_cpu(rsp);
+       return 0;
+}
+
+int rcutree_dead_cpu(unsigned int cpu)
+{
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp) {
+               rcu_cleanup_dead_cpu(cpu, rsp);
+               do_nocb_deferred_wakeup(per_cpu_ptr(rsp->rda, cpu));
+       }
+       return 0;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -3851,52 +3897,6 @@ void rcu_report_dead(unsigned int cpu)
 }
 #endif
 
-/*
- * Handle CPU online/offline notification events.
- */
-int rcu_cpu_notify(struct notifier_block *self,
-                  unsigned long action, void *hcpu)
-{
-       long cpu = (long)hcpu;
-       struct rcu_data *rdp = per_cpu_ptr(rcu_state_p->rda, cpu);
-       struct rcu_node *rnp = rdp->mynode;
-       struct rcu_state *rsp;
-
-       switch (action) {
-       case CPU_UP_PREPARE:
-       case CPU_UP_PREPARE_FROZEN:
-               rcu_prepare_cpu(cpu);
-               rcu_prepare_kthreads(cpu);
-               rcu_spawn_all_nocb_kthreads(cpu);
-               break;
-       case CPU_ONLINE:
-       case CPU_DOWN_FAILED:
-               sync_sched_exp_online_cleanup(cpu);
-               rcu_boost_kthread_setaffinity(rnp, -1);
-               break;
-       case CPU_DOWN_PREPARE:
-               rcu_boost_kthread_setaffinity(rnp, cpu);
-               break;
-       case CPU_DYING:
-       case CPU_DYING_FROZEN:
-               for_each_rcu_flavor(rsp)
-                       rcu_cleanup_dying_cpu(rsp);
-               break;
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-       case CPU_UP_CANCELED:
-       case CPU_UP_CANCELED_FROZEN:
-               for_each_rcu_flavor(rsp) {
-                       rcu_cleanup_dead_cpu(cpu, rsp);
-                       do_nocb_deferred_wakeup(per_cpu_ptr(rsp->rda, cpu));
-               }
-               break;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
-}
-
 static int rcu_pm_notify(struct notifier_block *self,
                         unsigned long action, void *hcpu)
 {
@@ -4208,10 +4208,9 @@ void __init rcu_init(void)
         * this is called early in boot, before either interrupts
         * or the scheduler are operational.
         */
-       cpu_notifier(rcu_cpu_notify, 0);
        pm_notifier(rcu_pm_notify, 0);
        for_each_online_cpu(cpu)
-               rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
+               rcutree_prepare_cpu(cpu);
 }
 
 #include "tree_exp.h"