1 From fdb99949a781d0c3d919eb30189de91650c02641 Mon Sep 17 00:00:00 2001
2 From: Thomas Gleixner <tglx@linutronix.de>
3 Date: Wed, 5 Oct 2011 11:59:38 -0700
4 Subject: [PATCH 130/365] rcu: Merge RCU-bh into RCU-preempt
6 The Linux kernel has long RCU-bh read-side critical sections that
7 intolerably increase scheduling latency under mainline's RCU-bh rules,
8 which include RCU-bh read-side critical sections being non-preemptible.
9 This patch therefore arranges for RCU-bh to be implemented in terms of
10 RCU-preempt for CONFIG_PREEMPT_RT_FULL=y.
12 This has the downside of defeating the purpose of RCU-bh, namely,
13 handling the case where the system is subjected to a network-based
14 denial-of-service attack that keeps at least one CPU doing full-time
15 softirq processing. This issue will be fixed by a later commit.
17 The current commit will need some work to make it appropriate for
18 mainline use, for example, it needs to be extended to cover Tiny RCU.
20 [ paulmck: Added a useful changelog ]
22 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
23 Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
24 Link: http://lkml.kernel.org/r/20111005185938.GA20403@linux.vnet.ibm.com
25 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
27 include/linux/rcupdate.h | 23 +++++++++++++++++++++++
28 include/linux/rcutree.h | 18 ++++++++++++++++--
29 kernel/rcu/tree.c | 16 ++++++++++++++++
30 kernel/rcu/update.c | 2 ++
31 4 files changed, 57 insertions(+), 2 deletions(-)
33 diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
34 index 1eef045..ddacc7e 100644
35 --- a/include/linux/rcupdate.h
36 +++ b/include/linux/rcupdate.h
37 @@ -169,6 +169,9 @@ void call_rcu(struct rcu_head *head,
39 #endif /* #else #ifdef CONFIG_PREEMPT_RCU */
41 +#ifdef CONFIG_PREEMPT_RT_FULL
42 +#define call_rcu_bh call_rcu
45 * call_rcu_bh() - Queue an RCU for invocation after a quicker grace period.
46 * @head: structure to be used for queueing the RCU updates.
47 @@ -192,6 +195,7 @@ void call_rcu(struct rcu_head *head,
49 void call_rcu_bh(struct rcu_head *head,
54 * call_rcu_sched() - Queue an RCU for invocation after sched grace period.
55 @@ -330,7 +334,11 @@ static inline int rcu_preempt_depth(void)
57 void rcu_end_inkernel_boot(void);
58 void rcu_sched_qs(void);
59 +#ifdef CONFIG_PREEMPT_RT_FULL
60 +static inline void rcu_bh_qs(void) { }
64 void rcu_check_callbacks(int user);
65 struct notifier_block;
66 int rcu_cpu_notify(struct notifier_block *self,
67 @@ -496,7 +504,14 @@ extern struct lockdep_map rcu_callback_map;
68 int debug_lockdep_rcu_enabled(void);
70 int rcu_read_lock_held(void);
71 +#ifdef CONFIG_PREEMPT_RT_FULL
72 +static inline int rcu_read_lock_bh_held(void)
74 + return rcu_read_lock_held();
77 int rcu_read_lock_bh_held(void);
81 * rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section?
82 @@ -944,10 +959,14 @@ static inline void rcu_read_unlock(void)
83 static inline void rcu_read_lock_bh(void)
86 +#ifdef CONFIG_PREEMPT_RT_FULL
90 rcu_lock_acquire(&rcu_bh_lock_map);
91 RCU_LOCKDEP_WARN(!rcu_is_watching(),
92 "rcu_read_lock_bh() used illegally while idle");
97 @@ -957,10 +976,14 @@ static inline void rcu_read_lock_bh(void)
99 static inline void rcu_read_unlock_bh(void)
101 +#ifdef CONFIG_PREEMPT_RT_FULL
104 RCU_LOCKDEP_WARN(!rcu_is_watching(),
105 "rcu_read_unlock_bh() used illegally while idle");
106 rcu_lock_release(&rcu_bh_lock_map);
112 diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
113 index 60d15a0..436c9e6 100644
114 --- a/include/linux/rcutree.h
115 +++ b/include/linux/rcutree.h
116 @@ -44,7 +44,11 @@ static inline void rcu_virt_note_context_switch(int cpu)
117 rcu_note_context_switch();
120 +#ifdef CONFIG_PREEMPT_RT_FULL
121 +# define synchronize_rcu_bh synchronize_rcu
123 void synchronize_rcu_bh(void);
125 void synchronize_sched_expedited(void);
126 void synchronize_rcu_expedited(void);
128 @@ -72,7 +76,11 @@ static inline void synchronize_rcu_bh_expedited(void)
131 void rcu_barrier(void);
132 +#ifdef CONFIG_PREEMPT_RT_FULL
133 +# define rcu_barrier_bh rcu_barrier
135 void rcu_barrier_bh(void);
137 void rcu_barrier_sched(void);
138 unsigned long get_state_synchronize_rcu(void);
139 void cond_synchronize_rcu(unsigned long oldstate);
140 @@ -85,12 +93,10 @@ unsigned long rcu_batches_started(void);
141 unsigned long rcu_batches_started_bh(void);
142 unsigned long rcu_batches_started_sched(void);
143 unsigned long rcu_batches_completed(void);
144 -unsigned long rcu_batches_completed_bh(void);
145 unsigned long rcu_batches_completed_sched(void);
146 void show_rcu_gp_kthreads(void);
148 void rcu_force_quiescent_state(void);
149 -void rcu_bh_force_quiescent_state(void);
150 void rcu_sched_force_quiescent_state(void);
152 void rcu_idle_enter(void);
153 @@ -105,6 +111,14 @@ extern int rcu_scheduler_active __read_mostly;
155 bool rcu_is_watching(void);
157 +#ifndef CONFIG_PREEMPT_RT_FULL
158 +void rcu_bh_force_quiescent_state(void);
159 +unsigned long rcu_batches_completed_bh(void);
161 +# define rcu_bh_force_quiescent_state rcu_force_quiescent_state
162 +# define rcu_batches_completed_bh rcu_batches_completed
165 void rcu_all_qs(void);
167 #endif /* __LINUX_RCUTREE_H */
168 diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
169 index f07343b..d52db2c 100644
170 --- a/kernel/rcu/tree.c
171 +++ b/kernel/rcu/tree.c
172 @@ -266,6 +266,7 @@ void rcu_sched_qs(void)
176 +#ifndef CONFIG_PREEMPT_RT_FULL
179 if (__this_cpu_read(rcu_bh_data.cpu_no_qs.s)) {
180 @@ -275,6 +276,7 @@ void rcu_bh_qs(void)
181 __this_cpu_write(rcu_bh_data.cpu_no_qs.b.norm, false);
186 static DEFINE_PER_CPU(int, rcu_sched_qs_mask);
188 @@ -459,6 +461,7 @@ unsigned long rcu_batches_completed_sched(void)
190 EXPORT_SYMBOL_GPL(rcu_batches_completed_sched);
192 +#ifndef CONFIG_PREEMPT_RT_FULL
194 * Return the number of RCU BH batches completed thus far for debug & stats.
196 @@ -486,6 +489,13 @@ void rcu_bh_force_quiescent_state(void)
198 EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
201 +void rcu_force_quiescent_state(void)
204 +EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
208 * Force a quiescent state for RCU-sched.
210 @@ -3114,6 +3124,7 @@ void call_rcu_sched(struct rcu_head *head, rcu_callback_t func)
212 EXPORT_SYMBOL_GPL(call_rcu_sched);
214 +#ifndef CONFIG_PREEMPT_RT_FULL
216 * Queue an RCU callback for invocation after a quicker grace period.
218 @@ -3122,6 +3133,7 @@ void call_rcu_bh(struct rcu_head *head, rcu_callback_t func)
219 __call_rcu(head, func, &rcu_bh_state, -1, 0);
221 EXPORT_SYMBOL_GPL(call_rcu_bh);
225 * Queue an RCU callback for lazy invocation after a grace period.
226 @@ -3213,6 +3225,7 @@ void synchronize_sched(void)
228 EXPORT_SYMBOL_GPL(synchronize_sched);
230 +#ifndef CONFIG_PREEMPT_RT_FULL
232 * synchronize_rcu_bh - wait until an rcu_bh grace period has elapsed.
234 @@ -3239,6 +3252,7 @@ void synchronize_rcu_bh(void)
235 wait_rcu_gp(call_rcu_bh);
237 EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
241 * get_state_synchronize_rcu - Snapshot current RCU state
242 @@ -4101,6 +4115,7 @@ static void _rcu_barrier(struct rcu_state *rsp)
243 mutex_unlock(&rsp->barrier_mutex);
246 +#ifndef CONFIG_PREEMPT_RT_FULL
248 * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete.
250 @@ -4109,6 +4124,7 @@ void rcu_barrier_bh(void)
251 _rcu_barrier(&rcu_bh_state);
253 EXPORT_SYMBOL_GPL(rcu_barrier_bh);
257 * rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks.
258 diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
259 index 5f748c5..9a39046 100644
260 --- a/kernel/rcu/update.c
261 +++ b/kernel/rcu/update.c
262 @@ -276,6 +276,7 @@ int rcu_read_lock_held(void)
264 EXPORT_SYMBOL_GPL(rcu_read_lock_held);
266 +#ifndef CONFIG_PREEMPT_RT_FULL
268 * rcu_read_lock_bh_held() - might we be in RCU-bh read-side critical section?
270 @@ -302,6 +303,7 @@ int rcu_read_lock_bh_held(void)
271 return in_softirq() || irqs_disabled();
273 EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held);
276 #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */