aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutree.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2012-02-23 16:30:16 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2012-04-24 23:54:53 -0400
commit6d8133919bac4270883b24328500875a49e71b36 (patch)
treeeae66c4640e429446ef254e468fafb9ceadb142b /kernel/rcutree.c
parentdabb8aa96020bde8359bc73e76c484dd7ff9b7f2 (diff)
rcu: Document why rcu_blocking_is_gp() is safe
The rcu_blocking_is_gp() function tests to see if there is only one online CPU, and if so, synchronize_sched() and friends become no-ops. However, for larger systems, num_online_cpus() scans a large vector, and might be preempted while doing so. While preempted, any number of CPUs might come online and go offline, potentially resulting in num_online_cpus() returning 1 when there never had only been one CPU online. This could result in a too-short RCU grace period, which could in turn result in total failure, except that the only way that the grace period is too short is if there is an RCU read-side critical section spanning it. For RCU-sched and RCU-bh (which are the only cases using rcu_blocking_is_gp()), RCU read-side critical sections have either preemption or bh disabled, which prevents CPUs from going offline. This in turn prevents actual failures from occurring. This commit therefore adds a large block comment to rcu_blocking_is_gp() documenting why it is safe. This commit also moves rcu_blocking_is_gp() into kernel/rcutree.c, which should help prevent unwary developers from mistaking it for a generally useful function. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r--kernel/rcutree.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 780acf8e15e9..8f6a344306e6 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1894,6 +1894,38 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
1894} 1894}
1895EXPORT_SYMBOL_GPL(call_rcu_bh); 1895EXPORT_SYMBOL_GPL(call_rcu_bh);
1896 1896
1897/*
1898 * Because a context switch is a grace period for RCU-sched and RCU-bh,
1899 * any blocking grace-period wait automatically implies a grace period
1900 * if there is only one CPU online at any point time during execution
1901 * of either synchronize_sched() or synchronize_rcu_bh(). It is OK to
1902 * occasionally incorrectly indicate that there are multiple CPUs online
1903 * when there was in fact only one the whole time, as this just adds
1904 * some overhead: RCU still operates correctly.
1905 *
1906 * Of course, sampling num_online_cpus() with preemption enabled can
1907 * give erroneous results if there are concurrent CPU-hotplug operations.
1908 * For example, given a demonic sequence of preemptions in num_online_cpus()
1909 * and CPU-hotplug operations, there could be two or more CPUs online at
1910 * all times, but num_online_cpus() might well return one (or even zero).
1911 *
1912 * However, all such demonic sequences require at least one CPU-offline
1913 * operation. Furthermore, rcu_blocking_is_gp() giving the wrong answer
1914 * is only a problem if there is an RCU read-side critical section executing
1915 * throughout. But RCU-sched and RCU-bh read-side critical sections
1916 * disable either preemption or bh, which prevents a CPU from going offline.
1917 * Therefore, the only way that rcu_blocking_is_gp() can incorrectly return
1918 * that there is only one CPU when in fact there was more than one throughout
1919 * is when there were no RCU readers in the system. If there are no
1920 * RCU readers, the grace period by definition can be of zero length,
1921 * regardless of the number of online CPUs.
1922 */
1923static inline int rcu_blocking_is_gp(void)
1924{
1925 might_sleep(); /* Check for RCU read-side critical section. */
1926 return num_online_cpus() <= 1;
1927}
1928
1897/** 1929/**
1898 * synchronize_sched - wait until an rcu-sched grace period has elapsed. 1930 * synchronize_sched - wait until an rcu-sched grace period has elapsed.
1899 * 1931 *