aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcu
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2015-10-07 12:10:48 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2015-12-04 15:27:31 -0500
commit46a5d164db53ba6066b11889abb7fa6bddbe5cf7 (patch)
tree37e726508f20e8dd951f04dd3266be912abc5b44 /kernel/rcu
parentf0f2e7d307fff226e0c1df5a07101a1216a46d8a (diff)
rcu: Stop disabling interrupts in scheduler fastpaths
We need the scheduler's fastpaths to be, well, fast, and unnecessarily disabling and re-enabling interrupts is not necessarily consistent with this goal. Especially given that there are regions of the scheduler that already have interrupts disabled. This commit therefore moves the call to rcu_note_context_switch() to one of the interrupts-disabled regions of the scheduler, and removes the now-redundant disabling and re-enabling of interrupts from rcu_note_context_switch() and the functions it calls. Reported-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> [ paulmck: Shift rcu_note_context_switch() to avoid deadlock, as suggested by Peter Zijlstra. ]
Diffstat (limited to 'kernel/rcu')
-rw-r--r--kernel/rcu/tree.c27
-rw-r--r--kernel/rcu/tree_plugin.h14
2 files changed, 18 insertions, 23 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index ed3bc0578cc5..93941d3434ad 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -242,8 +242,6 @@ static int rcu_gp_in_progress(struct rcu_state *rsp)
242 */ 242 */
243void rcu_sched_qs(void) 243void rcu_sched_qs(void)
244{ 244{
245 unsigned long flags;
246
247 if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.s)) 245 if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.s))
248 return; 246 return;
249 trace_rcu_grace_period(TPS("rcu_sched"), 247 trace_rcu_grace_period(TPS("rcu_sched"),
@@ -252,13 +250,9 @@ void rcu_sched_qs(void)
252 __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false); 250 __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false);
253 if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) 251 if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))
254 return; 252 return;
255 local_irq_save(flags); 253 __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false);
256 if (__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) { 254 rcu_report_exp_rdp(&rcu_sched_state,
257 __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false); 255 this_cpu_ptr(&rcu_sched_data), true);
258 rcu_report_exp_rdp(&rcu_sched_state,
259 this_cpu_ptr(&rcu_sched_data), true);
260 }
261 local_irq_restore(flags);
262} 256}
263 257
264void rcu_bh_qs(void) 258void rcu_bh_qs(void)
@@ -295,17 +289,16 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);
295 * We inform the RCU core by emulating a zero-duration dyntick-idle 289 * We inform the RCU core by emulating a zero-duration dyntick-idle
296 * period, which we in turn do by incrementing the ->dynticks counter 290 * period, which we in turn do by incrementing the ->dynticks counter
297 * by two. 291 * by two.
292 *
293 * The caller must have disabled interrupts.
298 */ 294 */
299static void rcu_momentary_dyntick_idle(void) 295static void rcu_momentary_dyntick_idle(void)
300{ 296{
301 unsigned long flags;
302 struct rcu_data *rdp; 297 struct rcu_data *rdp;
303 struct rcu_dynticks *rdtp; 298 struct rcu_dynticks *rdtp;
304 int resched_mask; 299 int resched_mask;
305 struct rcu_state *rsp; 300 struct rcu_state *rsp;
306 301
307 local_irq_save(flags);
308
309 /* 302 /*
310 * Yes, we can lose flag-setting operations. This is OK, because 303 * Yes, we can lose flag-setting operations. This is OK, because
311 * the flag will be set again after some delay. 304 * the flag will be set again after some delay.
@@ -335,13 +328,12 @@ static void rcu_momentary_dyntick_idle(void)
335 smp_mb__after_atomic(); /* Later stuff after QS. */ 328 smp_mb__after_atomic(); /* Later stuff after QS. */
336 break; 329 break;
337 } 330 }
338 local_irq_restore(flags);
339} 331}
340 332
341/* 333/*
342 * Note a context switch. This is a quiescent state for RCU-sched, 334 * Note a context switch. This is a quiescent state for RCU-sched,
343 * and requires special handling for preemptible RCU. 335 * and requires special handling for preemptible RCU.
344 * The caller must have disabled preemption. 336 * The caller must have disabled interrupts.
345 */ 337 */
346void rcu_note_context_switch(void) 338void rcu_note_context_switch(void)
347{ 339{
@@ -371,9 +363,14 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);
371 */ 363 */
372void rcu_all_qs(void) 364void rcu_all_qs(void)
373{ 365{
366 unsigned long flags;
367
374 barrier(); /* Avoid RCU read-side critical sections leaking down. */ 368 barrier(); /* Avoid RCU read-side critical sections leaking down. */
375 if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) 369 if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) {
370 local_irq_save(flags);
376 rcu_momentary_dyntick_idle(); 371 rcu_momentary_dyntick_idle();
372 local_irq_restore(flags);
373 }
377 this_cpu_inc(rcu_qs_ctr); 374 this_cpu_inc(rcu_qs_ctr);
378 barrier(); /* Avoid RCU read-side critical sections leaking up. */ 375 barrier(); /* Avoid RCU read-side critical sections leaking up. */
379} 376}
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 8e9d4a4d0326..e6da888cc908 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -146,8 +146,8 @@ static void __init rcu_bootup_announce(void)
146 * the corresponding expedited grace period will also be the end of the 146 * the corresponding expedited grace period will also be the end of the
147 * normal grace period. 147 * normal grace period.
148 */ 148 */
149static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp, 149static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp)
150 unsigned long flags) __releases(rnp->lock) 150 __releases(rnp->lock) /* But leaves rrupts disabled. */
151{ 151{
152 int blkd_state = (rnp->gp_tasks ? RCU_GP_TASKS : 0) + 152 int blkd_state = (rnp->gp_tasks ? RCU_GP_TASKS : 0) +
153 (rnp->exp_tasks ? RCU_EXP_TASKS : 0) + 153 (rnp->exp_tasks ? RCU_EXP_TASKS : 0) +
@@ -235,7 +235,7 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
235 rnp->gp_tasks = &t->rcu_node_entry; 235 rnp->gp_tasks = &t->rcu_node_entry;
236 if (!rnp->exp_tasks && (blkd_state & RCU_EXP_BLKD)) 236 if (!rnp->exp_tasks && (blkd_state & RCU_EXP_BLKD))
237 rnp->exp_tasks = &t->rcu_node_entry; 237 rnp->exp_tasks = &t->rcu_node_entry;
238 raw_spin_unlock(&rnp->lock); 238 raw_spin_unlock(&rnp->lock); /* rrupts remain disabled. */
239 239
240 /* 240 /*
241 * Report the quiescent state for the expedited GP. This expedited 241 * Report the quiescent state for the expedited GP. This expedited
@@ -250,7 +250,6 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
250 } else { 250 } else {
251 WARN_ON_ONCE(t->rcu_read_unlock_special.b.exp_need_qs); 251 WARN_ON_ONCE(t->rcu_read_unlock_special.b.exp_need_qs);
252 } 252 }
253 local_irq_restore(flags);
254} 253}
255 254
256/* 255/*
@@ -285,12 +284,11 @@ static void rcu_preempt_qs(void)
285 * predating the current grace period drain, in other words, until 284 * predating the current grace period drain, in other words, until
286 * rnp->gp_tasks becomes NULL. 285 * rnp->gp_tasks becomes NULL.
287 * 286 *
288 * Caller must disable preemption. 287 * Caller must disable interrupts.
289 */ 288 */
290static void rcu_preempt_note_context_switch(void) 289static void rcu_preempt_note_context_switch(void)
291{ 290{
292 struct task_struct *t = current; 291 struct task_struct *t = current;
293 unsigned long flags;
294 struct rcu_data *rdp; 292 struct rcu_data *rdp;
295 struct rcu_node *rnp; 293 struct rcu_node *rnp;
296 294
@@ -300,7 +298,7 @@ static void rcu_preempt_note_context_switch(void)
300 /* Possibly blocking in an RCU read-side critical section. */ 298 /* Possibly blocking in an RCU read-side critical section. */
301 rdp = this_cpu_ptr(rcu_state_p->rda); 299 rdp = this_cpu_ptr(rcu_state_p->rda);
302 rnp = rdp->mynode; 300 rnp = rdp->mynode;
303 raw_spin_lock_irqsave_rcu_node(rnp, flags); 301 raw_spin_lock_rcu_node(rnp);
304 t->rcu_read_unlock_special.b.blocked = true; 302 t->rcu_read_unlock_special.b.blocked = true;
305 t->rcu_blocked_node = rnp; 303 t->rcu_blocked_node = rnp;
306 304
@@ -316,7 +314,7 @@ static void rcu_preempt_note_context_switch(void)
316 (rnp->qsmask & rdp->grpmask) 314 (rnp->qsmask & rdp->grpmask)
317 ? rnp->gpnum 315 ? rnp->gpnum
318 : rnp->gpnum + 1); 316 : rnp->gpnum + 1);
319 rcu_preempt_ctxt_queue(rnp, rdp, flags); 317 rcu_preempt_ctxt_queue(rnp, rdp);
320 } else if (t->rcu_read_lock_nesting < 0 && 318 } else if (t->rcu_read_lock_nesting < 0 &&
321 t->rcu_read_unlock_special.s) { 319 t->rcu_read_unlock_special.s) {
322 320