diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2012-06-19 14:58:27 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2012-07-02 15:34:25 -0400 |
commit | 95f0c1de3e6ed4383cc4b5f52ce4ecfb21026b49 (patch) | |
tree | 8099a405c03d9caabbf8f1752346e0aa0e30ee28 /kernel/rcutree.c | |
parent | 1c17e4d4437d8045a596d9f06c1558dc09e2b372 (diff) |
rcu: Disable preemption in rcu_blocking_is_gp()
It is time to optimize CONFIG_TREE_PREEMPT_RCU's synchronize_rcu()
for uniprocessor optimization, which means that rcu_blocking_is_gp()
can no longer rely on RCU read-side critical sections having disabled
preemption. This commit therefore disables preemption across
rcu_blocking_is_gp()'s scan of the cpu_online_mask.
(Updated from previous version to fix embarrassing bug spotted by
Wu Fengguang.)
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r-- | kernel/rcutree.c | 24 |
1 files changed, 6 insertions, 18 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 70c4da7d2a97..e000a623e635 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -1981,28 +1981,16 @@ EXPORT_SYMBOL_GPL(call_rcu_bh); | |||
1981 | * occasionally incorrectly indicate that there are multiple CPUs online | 1981 | * occasionally incorrectly indicate that there are multiple CPUs online |
1982 | * when there was in fact only one the whole time, as this just adds | 1982 | * when there was in fact only one the whole time, as this just adds |
1983 | * some overhead: RCU still operates correctly. | 1983 | * some overhead: RCU still operates correctly. |
1984 | * | ||
1985 | * Of course, sampling num_online_cpus() with preemption enabled can | ||
1986 | * give erroneous results if there are concurrent CPU-hotplug operations. | ||
1987 | * For example, given a demonic sequence of preemptions in num_online_cpus() | ||
1988 | * and CPU-hotplug operations, there could be two or more CPUs online at | ||
1989 | * all times, but num_online_cpus() might well return one (or even zero). | ||
1990 | * | ||
1991 | * However, all such demonic sequences require at least one CPU-offline | ||
1992 | * operation. Furthermore, rcu_blocking_is_gp() giving the wrong answer | ||
1993 | * is only a problem if there is an RCU read-side critical section executing | ||
1994 | * throughout. But RCU-sched and RCU-bh read-side critical sections | ||
1995 | * disable either preemption or bh, which prevents a CPU from going offline. | ||
1996 | * Therefore, the only way that rcu_blocking_is_gp() can incorrectly return | ||
1997 | * that there is only one CPU when in fact there was more than one throughout | ||
1998 | * is when there were no RCU readers in the system. If there are no | ||
1999 | * RCU readers, the grace period by definition can be of zero length, | ||
2000 | * regardless of the number of online CPUs. | ||
2001 | */ | 1984 | */ |
2002 | static inline int rcu_blocking_is_gp(void) | 1985 | static inline int rcu_blocking_is_gp(void) |
2003 | { | 1986 | { |
1987 | int ret; | ||
1988 | |||
2004 | might_sleep(); /* Check for RCU read-side critical section. */ | 1989 | might_sleep(); /* Check for RCU read-side critical section. */ |
2005 | return num_online_cpus() <= 1; | 1990 | preempt_disable(); |
1991 | ret = num_online_cpus() <= 1; | ||
1992 | preempt_enable(); | ||
1993 | return ret; | ||
2006 | } | 1994 | } |
2007 | 1995 | ||
2008 | /** | 1996 | /** |