CPU hotplug changes for 4.9
Subsystems (3)
cover CPU hotplug changes for 4.9
Hello!
This series contains a few CPU-hotplug updates:
1. Provide exact tracking of incoming CPUs, which means that there
is now a definite point in the CPU-hotplug code at which RCU starts paying attention to incoming CPUs.
2. Get rid of obsolete CPU_STARTING reference, courtesy of Sebastian
Andrzej Siewior.
3. Convert rcutorture's CPU-hotplug handling to use the shiny new
state machine, courtesy of Sebastian Andrzej Siewior.
Thanx, Paul
------------------------------------------------------------------------
include/linux/rcupdate.h | 1 kernel/cpu.c | 3 +- kernel/rcu/rcutorture.c | 52 ++++++++++++----------------------------------- kernel/rcu/tree.c | 32 ++++++++++++++++++++++++++-- 4 files changed, 46 insertions(+), 42 deletions(-)
PATCH 1/3 rcu: Exact CPU-online tracking for RCU
Up to now, RCU has assumed that the CPU-online process makes it from CPU_UP_PREPARE to set_cpu_online() within one jiffy. Given the recent rise of virtualized environments, this assumption is very clearly obsolete.
This commit therefore updates RCU's internal CPU state-tracking information at notify_cpu_starting() time, thus providing exact tracking of the CPU state from an RCU perspective.
Note that this means that incoming CPUs must not use RCU read-side critical section (other than those of SRCU) until notify_cpu_starting() time. Note that the CPU_STARTING notifiers -are- allowed to use RCU read-side critical sections.
If a given architecture or CPU family needs to use RCU read-side critical sections earlier, the call to rcu_cpu_starting() from notify_cpu_starting() will need to be architecture-specific, with architectures that opt out being required to hand-place the call to rcu_cpu_starting() at some point preceding the call to notify_cpu_starting().
--- include/linux/rcupdate.h | 1 + kernel/cpu.c | 1 + kernel/rcu/tree.c | 32 +++++++++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 3 deletions(-)
include/linux/rcupdate.h +1 -0
@@ -334,6 +334,7 @@ void rcu_sched_qs(void);void rcu_bh_qs (void );void rcu_check_callbacks (int user);void rcu_report_dead (unsigned int cpu); +void rcu_cpu_starting (unsigned int cpu);#ifndef CONFIG_TINY_RCU void rcu_end_inkernel_boot (void );
kernel/cpu.c +1 -0
@@ -889,6 +889,7 @@ void notify_cpu_starting(unsigned int cpu)struct cpuhp_cpu_state *st =per_cpu_ptr (&cpuhp_state, cpu);enum cpuhp_state target =min ((int )st->target,CPUHP_AP_ONLINE ); +rcu_cpu_starting (cpu);/* All CPU_STARTING notifiers can use RCU. */ while (st->state < target) {struct cpuhp_step *step;
kernel/rcu/tree.c +29 -3
@@ -3792,8 +3792,6 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) rnp = rdp->mynode; mask = rdp->grpmask;raw_spin_lock_rcu_node (rnp);/* irqs already disabled. */ - rnp->qsmaskinitnext |= mask; - rnp->expmaskinitnext |= mask;if (!rdp->beenonline)WRITE_ONCE (rsp->ncpus,READ_ONCE (rsp->ncpus) +1 ); rdp->beenonline = true;/* We have now been online. */
@@ -3860,6 +3858,32 @@ int rcutree_dead_cpu(unsigned int cpu)return 0 ; } +/* +* Mark the specified CPU as being online so that subsequent grace periods +* (both expedited and normal) will wait on it. Note that this means that +* incoming CPUs are not allowed to use RCU read-side critical sections +* until this function is called. Failing to observe this restriction +* will result in lockdep splats. +*/ +void rcu_cpu_starting (unsigned int cpu) +{ +unsigned long flags; +unsigned long mask; +struct rcu_data *rdp; +struct rcu_node *rnp; +struct rcu_state *rsp; + +for_each_rcu_flavor (rsp) { + rdp =this_cpu_ptr (rsp->rda); + rnp = rdp->mynode; + mask = rdp->grpmask; +raw_spin_lock_irqsave_rcu_node (rnp, flags); + rnp->qsmaskinitnext |= mask; + rnp->expmaskinitnext |= mask; +raw_spin_unlock_irqrestore_rcu_node (rnp, flags); + } +} +#ifdef CONFIG_HOTPLUG_CPU /* * The CPU is exiting the idle loop into the arch_cpu_idle_dead()
@@ -4209,8 +4233,10 @@ void __init rcu_init(void)* or the scheduler are operational. */ pm_notifier (rcu_pm_notify,0 ); -for_each_online_cpu (cpu) +for_each_online_cpu (cpu) {rcutree_prepare_cpu (cpu); +rcu_cpu_starting (cpu); + } }#include "tree_exp.h"
Signature · 1 line
2.5.2
PATCH 2/3 cpu/hotplug: Get rid of CPU_STARTING reference
In reply to Paul E. McKenneyFrom: Sebastian Andrzej Siewior <[email protected]>
CPU_STARTING is scheduled for removal. There is no use of it in drivers and just compatibility use core code. This patch removes it from an RCU-related comment.
--- kernel/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cpu.c +1 -1
@@ -889,7 +889,7 @@ void notify_cpu_starting(unsigned int cpu)struct cpuhp_cpu_state *st =per_cpu_ptr (&cpuhp_state, cpu);enum cpuhp_state target =min ((int )st->target,CPUHP_AP_ONLINE ); -rcu_cpu_starting (cpu);/* All CPU_STARTING notifiers can use RCU. */ +rcu_cpu_starting (cpu);/* Enables RCU usage on this CPU. */ while (st->state < target) {struct cpuhp_step *step;
Signature · 1 line
2.5.2
PATCH 3/3 rcutorture: Convert to hotplug state machine
In reply to Paul E. McKenneyFrom: Sebastian Andrzej Siewior <[email protected]>
Install the callbacks via the state machine and let the core invoke the callbacks on the already online CPUs.
--- kernel/rcu/rcutorture.c | 52 +++++++++++++------------------------------------ 1 file changed, 14 insertions(+), 38 deletions(-)
kernel/rcu/rcutorture.c +14 -38
@@ -1362,12 +1362,12 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag) onoff_interval, onoff_holdoff); } -static void rcutorture_booster_cleanup (int cpu) +static int rcutorture_booster_cleanup (unsigned int cpu) {struct task_struct *t;if (boost_tasks[cpu] ==NULL ) -return ; +return 0 ;mutex_lock (&boost_mutex); t = boost_tasks[cpu]; boost_tasks[cpu] =NULL ;
@@ -1375,9 +1375,10 @@ static void rcutorture_booster_cleanup(int cpu)/* This must be outside of the mutex, otherwise deadlock! */ torture_stop_kthread (rcu_torture_boost, t); +return 0 ; } -static int rcutorture_booster_init (int cpu) +static int rcutorture_booster_init (unsigned int cpu) {int retval;
@@ -1577,28 +1578,7 @@ static void rcu_torture_barrier_cleanup(void) } } -static int rcutorture_cpu_notify (struct notifier_block *self, -unsigned long action,void *hcpu) -{ -long cpu = (long )hcpu; - -switch (action & ~CPU_TASKS_FROZEN ) { -case CPU_ONLINE : -case CPU_DOWN_FAILED : - (void )rcutorture_booster_init (cpu); -break ; -case CPU_DOWN_PREPARE : -rcutorture_booster_cleanup (cpu); -break ; -default : -break ; - } -return NOTIFY_OK ; -} - -static struct notifier_block rcutorture_cpu_nb = { - .notifier_call = rcutorture_cpu_notify, -}; +static enum cpuhp_state rcutor_hp;static void rcu_torture_cleanup (void )
@@ -1638,11 +1618,8 @@ rcu_torture_cleanup(void)for (i =0 ; i < ncbflooders; i++)torture_stop_kthread (rcu_torture_cbflood, cbflood_task[i]);if ((test_boost ==1 && cur_ops->can_boost) || - test_boost ==2 ) { -unregister_cpu_notifier (&rcutorture_cpu_nb); -for_each_possible_cpu (i) -rcutorture_booster_cleanup (i); - } + test_boost ==2 ) +cpuhp_remove_state (rcutor_hp);/* * Wait for all RCU callbacks to fire, then do flavor-specific
@@ -1869,14 +1846,13 @@ rcu_torture_init(void) test_boost == 2) { boost_starttime = jiffies + test_boost_interval *HZ ; -register_cpu_notifier (&rcutorture_cpu_nb); -for_each_possible_cpu (i) { -if (cpu_is_offline (i)) -continue ;/* Heuristic: CPU can go offline. */ - firsterr =rcutorture_booster_init (i); -if (firsterr) - goto unwind; - } + + firsterr =cpuhp_setup_state (CPUHP_AP_ONLINE_DYN ,"RCU_TORTURE" , + rcutorture_booster_init, + rcutorture_booster_cleanup); +if (firsterr <0 ) + goto unwind; + rcutor_hp = firsterr; } firsterr =torture_shutdown_init (shutdown_secs, rcu_torture_cleanup);if (firsterr)
Signature · 1 line
2.5.2