Commit 5554788e authored by Paul E. McKenney's avatar Paul E. McKenney

rcu: Suppress false-positive offline-CPU lockdep-RCU splat

The rcu_lockdep_current_cpu_online() function currently checks only the
RCU-sched data structures to determine whether or not RCU believes that a
given CPU is offline.  Unfortunately, there are multiple flavors of RCU,
which means that there is a short window of time during which the various
flavors disagree as to whether or not a given CPU is offline.  This can
result in false-positive lockdep-RCU splats in which some other flavor
of RCU tries to do something based on its view that the CPU is online,
only to get hit with a lockdep-RCU splat because RCU-sched instead
believes that the CPU is offline.

This commit therefore changes rcu_lockdep_current_cpu_online() to scan
all RCU flavors and to consider a given CPU to be online if any of the
RCU flavors believe it to be online, thus preventing these false-positive
splats.
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent 92816435
...@@ -1030,41 +1030,41 @@ void rcu_request_urgent_qs_task(struct task_struct *t) ...@@ -1030,41 +1030,41 @@ void rcu_request_urgent_qs_task(struct task_struct *t)
#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU) #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU)
/* /*
* Is the current CPU online? Disable preemption to avoid false positives * Is the current CPU online as far as RCU is concerned?
* that could otherwise happen due to the current CPU number being sampled,
* this task being preempted, its old CPU being taken offline, resuming
* on some other CPU, then determining that its old CPU is now offline.
* It is OK to use RCU on an offline processor during initial boot, hence
* the check for rcu_scheduler_fully_active. Note also that it is OK
* for a CPU coming online to use RCU for one jiffy prior to marking itself
* online in the cpu_online_mask. Similarly, it is OK for a CPU going
* 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 teardown
* of the CPU.
* *
* This is also why RCU internally marks CPUs online during in the * Disable preemption to avoid false positives that could otherwise
* preparation phase and offline after the CPU has been taken down. * happen due to the current CPU number being sampled, this task being
* preempted, its old CPU being taken offline, resuming on some other CPU,
* then determining that its old CPU is now offline. Because there are
* multiple flavors of RCU, and because this function can be called in the
* midst of updating the flavors while a given CPU coming online or going
* offline, it is necessary to check all flavors. If any of the flavors
* believe that given CPU is online, it is considered to be online.
* *
* Disable checking if in an NMI handler because we cannot safely report * Disable checking if in an NMI handler because we cannot safely
* errors from NMI handlers anyway. * report errors from NMI handlers anyway. In addition, it is OK to use
* RCU on an offline processor during initial boot, hence the check for
* rcu_scheduler_fully_active.
*/ */
bool rcu_lockdep_current_cpu_online(void) bool rcu_lockdep_current_cpu_online(void)
{ {
struct rcu_data *rdp; struct rcu_data *rdp;
struct rcu_node *rnp; struct rcu_node *rnp;
bool ret; struct rcu_state *rsp;
if (in_nmi()) if (in_nmi() || !rcu_scheduler_fully_active)
return true; return true;
preempt_disable(); preempt_disable();
rdp = this_cpu_ptr(&rcu_sched_data); for_each_rcu_flavor(rsp) {
rnp = rdp->mynode; rdp = this_cpu_ptr(rsp->rda);
ret = (rdp->grpmask & rcu_rnp_online_cpus(rnp)) || rnp = rdp->mynode;
!rcu_scheduler_fully_active; if (rdp->grpmask & rcu_rnp_online_cpus(rnp)) {
preempt_enable();
return true;
}
}
preempt_enable(); preempt_enable();
return ret; return false;
} }
EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online); EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment