diff options
-rw-r--r-- | include/linux/rcutree.h | 7 | ||||
-rw-r--r-- | kernel/rcutree.c | 32 |
2 files changed, 32 insertions, 7 deletions
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index e8ee5dd0854c..b06363055ef8 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h | |||
@@ -98,13 +98,6 @@ extern void rcu_force_quiescent_state(void); | |||
98 | extern void rcu_bh_force_quiescent_state(void); | 98 | extern void rcu_bh_force_quiescent_state(void); |
99 | extern void rcu_sched_force_quiescent_state(void); | 99 | extern void rcu_sched_force_quiescent_state(void); |
100 | 100 | ||
101 | /* A context switch is a grace period for RCU-sched and RCU-bh. */ | ||
102 | static inline int rcu_blocking_is_gp(void) | ||
103 | { | ||
104 | might_sleep(); /* Check for RCU read-side critical section. */ | ||
105 | return num_online_cpus() == 1; | ||
106 | } | ||
107 | |||
108 | extern void rcu_scheduler_starting(void); | 101 | extern void rcu_scheduler_starting(void); |
109 | extern int rcu_scheduler_active __read_mostly; | 102 | extern int rcu_scheduler_active __read_mostly; |
110 | 103 | ||
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 | } |
1895 | EXPORT_SYMBOL_GPL(call_rcu_bh); | 1895 | EXPORT_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 | */ | ||
1923 | static 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 | * |