diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-05-27 06:38:52 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-05-28 11:41:05 -0400 |
commit | 29f742f88a32c9ab8cf6d9ba69e1ea918be5aa58 (patch) | |
tree | a38aa38c8025e050ec82a7e64d02dca07f90ffc7 /kernel | |
parent | f62508f68d04adefc4cf9b0177ba02c8818b3eec (diff) | |
parent | 23b5c8fa01b723c70a20d6e4ef4ff54c7656d6e1 (diff) |
Merge branch 'rcu/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu into core/urgent
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/rcutree.c | 130 | ||||
-rw-r--r-- | kernel/rcutree.h | 9 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 7 | ||||
-rw-r--r-- | kernel/rcutree_trace.c | 12 |
4 files changed, 68 insertions, 90 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index f07d2f03181a..8154a4a3491c 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch); | |||
163 | #ifdef CONFIG_NO_HZ | 163 | #ifdef CONFIG_NO_HZ |
164 | DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { | 164 | DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { |
165 | .dynticks_nesting = 1, | 165 | .dynticks_nesting = 1, |
166 | .dynticks = 1, | 166 | .dynticks = ATOMIC_INIT(1), |
167 | }; | 167 | }; |
168 | #endif /* #ifdef CONFIG_NO_HZ */ | 168 | #endif /* #ifdef CONFIG_NO_HZ */ |
169 | 169 | ||
@@ -322,13 +322,25 @@ void rcu_enter_nohz(void) | |||
322 | unsigned long flags; | 322 | unsigned long flags; |
323 | struct rcu_dynticks *rdtp; | 323 | struct rcu_dynticks *rdtp; |
324 | 324 | ||
325 | smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ | ||
326 | local_irq_save(flags); | 325 | local_irq_save(flags); |
327 | rdtp = &__get_cpu_var(rcu_dynticks); | 326 | rdtp = &__get_cpu_var(rcu_dynticks); |
328 | rdtp->dynticks++; | 327 | if (--rdtp->dynticks_nesting) { |
329 | rdtp->dynticks_nesting--; | 328 | local_irq_restore(flags); |
330 | WARN_ON_ONCE(rdtp->dynticks & 0x1); | 329 | return; |
330 | } | ||
331 | /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ | ||
332 | smp_mb__before_atomic_inc(); /* See above. */ | ||
333 | atomic_inc(&rdtp->dynticks); | ||
334 | smp_mb__after_atomic_inc(); /* Force ordering with next sojourn. */ | ||
335 | WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); | ||
331 | local_irq_restore(flags); | 336 | local_irq_restore(flags); |
337 | |||
338 | /* If the interrupt queued a callback, get out of dyntick mode. */ | ||
339 | if (in_irq() && | ||
340 | (__get_cpu_var(rcu_sched_data).nxtlist || | ||
341 | __get_cpu_var(rcu_bh_data).nxtlist || | ||
342 | rcu_preempt_needs_cpu(smp_processor_id()))) | ||
343 | set_need_resched(); | ||
332 | } | 344 | } |
333 | 345 | ||
334 | /* | 346 | /* |
@@ -344,11 +356,16 @@ void rcu_exit_nohz(void) | |||
344 | 356 | ||
345 | local_irq_save(flags); | 357 | local_irq_save(flags); |
346 | rdtp = &__get_cpu_var(rcu_dynticks); | 358 | rdtp = &__get_cpu_var(rcu_dynticks); |
347 | rdtp->dynticks++; | 359 | if (rdtp->dynticks_nesting++) { |
348 | rdtp->dynticks_nesting++; | 360 | local_irq_restore(flags); |
349 | WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); | 361 | return; |
362 | } | ||
363 | smp_mb__before_atomic_inc(); /* Force ordering w/previous sojourn. */ | ||
364 | atomic_inc(&rdtp->dynticks); | ||
365 | /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ | ||
366 | smp_mb__after_atomic_inc(); /* See above. */ | ||
367 | WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); | ||
350 | local_irq_restore(flags); | 368 | local_irq_restore(flags); |
351 | smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ | ||
352 | } | 369 | } |
353 | 370 | ||
354 | /** | 371 | /** |
@@ -362,11 +379,15 @@ void rcu_nmi_enter(void) | |||
362 | { | 379 | { |
363 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); | 380 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); |
364 | 381 | ||
365 | if (rdtp->dynticks & 0x1) | 382 | if (rdtp->dynticks_nmi_nesting == 0 && |
383 | (atomic_read(&rdtp->dynticks) & 0x1)) | ||
366 | return; | 384 | return; |
367 | rdtp->dynticks_nmi++; | 385 | rdtp->dynticks_nmi_nesting++; |
368 | WARN_ON_ONCE(!(rdtp->dynticks_nmi & 0x1)); | 386 | smp_mb__before_atomic_inc(); /* Force delay from prior write. */ |
369 | smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ | 387 | atomic_inc(&rdtp->dynticks); |
388 | /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ | ||
389 | smp_mb__after_atomic_inc(); /* See above. */ | ||
390 | WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); | ||
370 | } | 391 | } |
371 | 392 | ||
372 | /** | 393 | /** |
@@ -380,11 +401,14 @@ void rcu_nmi_exit(void) | |||
380 | { | 401 | { |
381 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); | 402 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); |
382 | 403 | ||
383 | if (rdtp->dynticks & 0x1) | 404 | if (rdtp->dynticks_nmi_nesting == 0 || |
405 | --rdtp->dynticks_nmi_nesting != 0) | ||
384 | return; | 406 | return; |
385 | smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ | 407 | /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ |
386 | rdtp->dynticks_nmi++; | 408 | smp_mb__before_atomic_inc(); /* See above. */ |
387 | WARN_ON_ONCE(rdtp->dynticks_nmi & 0x1); | 409 | atomic_inc(&rdtp->dynticks); |
410 | smp_mb__after_atomic_inc(); /* Force delay to next write. */ | ||
411 | WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); | ||
388 | } | 412 | } |
389 | 413 | ||
390 | /** | 414 | /** |
@@ -395,13 +419,7 @@ void rcu_nmi_exit(void) | |||
395 | */ | 419 | */ |
396 | void rcu_irq_enter(void) | 420 | void rcu_irq_enter(void) |
397 | { | 421 | { |
398 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); | 422 | rcu_exit_nohz(); |
399 | |||
400 | if (rdtp->dynticks_nesting++) | ||
401 | return; | ||
402 | rdtp->dynticks++; | ||
403 | WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); | ||
404 | smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ | ||
405 | } | 423 | } |
406 | 424 | ||
407 | /** | 425 | /** |
@@ -413,18 +431,7 @@ void rcu_irq_enter(void) | |||
413 | */ | 431 | */ |
414 | void rcu_irq_exit(void) | 432 | void rcu_irq_exit(void) |
415 | { | 433 | { |
416 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); | 434 | rcu_enter_nohz(); |
417 | |||
418 | if (--rdtp->dynticks_nesting) | ||
419 | return; | ||
420 | smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ | ||
421 | rdtp->dynticks++; | ||
422 | WARN_ON_ONCE(rdtp->dynticks & 0x1); | ||
423 | |||
424 | /* If the interrupt queued a callback, get out of dyntick mode. */ | ||
425 | if (__this_cpu_read(rcu_sched_data.nxtlist) || | ||
426 | __this_cpu_read(rcu_bh_data.nxtlist)) | ||
427 | set_need_resched(); | ||
428 | } | 435 | } |
429 | 436 | ||
430 | #ifdef CONFIG_SMP | 437 | #ifdef CONFIG_SMP |
@@ -436,19 +443,8 @@ void rcu_irq_exit(void) | |||
436 | */ | 443 | */ |
437 | static int dyntick_save_progress_counter(struct rcu_data *rdp) | 444 | static int dyntick_save_progress_counter(struct rcu_data *rdp) |
438 | { | 445 | { |
439 | int ret; | 446 | rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks); |
440 | int snap; | 447 | return 0; |
441 | int snap_nmi; | ||
442 | |||
443 | snap = rdp->dynticks->dynticks; | ||
444 | snap_nmi = rdp->dynticks->dynticks_nmi; | ||
445 | smp_mb(); /* Order sampling of snap with end of grace period. */ | ||
446 | rdp->dynticks_snap = snap; | ||
447 | rdp->dynticks_nmi_snap = snap_nmi; | ||
448 | ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0); | ||
449 | if (ret) | ||
450 | rdp->dynticks_fqs++; | ||
451 | return ret; | ||
452 | } | 448 | } |
453 | 449 | ||
454 | /* | 450 | /* |
@@ -459,16 +455,11 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp) | |||
459 | */ | 455 | */ |
460 | static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | 456 | static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) |
461 | { | 457 | { |
462 | long curr; | 458 | unsigned long curr; |
463 | long curr_nmi; | 459 | unsigned long snap; |
464 | long snap; | ||
465 | long snap_nmi; | ||
466 | 460 | ||
467 | curr = rdp->dynticks->dynticks; | 461 | curr = (unsigned long)atomic_add_return(0, &rdp->dynticks->dynticks); |
468 | snap = rdp->dynticks_snap; | 462 | snap = (unsigned long)rdp->dynticks_snap; |
469 | curr_nmi = rdp->dynticks->dynticks_nmi; | ||
470 | snap_nmi = rdp->dynticks_nmi_snap; | ||
471 | smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ | ||
472 | 463 | ||
473 | /* | 464 | /* |
474 | * If the CPU passed through or entered a dynticks idle phase with | 465 | * If the CPU passed through or entered a dynticks idle phase with |
@@ -478,8 +469,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
478 | * read-side critical section that started before the beginning | 469 | * read-side critical section that started before the beginning |
479 | * of the current RCU grace period. | 470 | * of the current RCU grace period. |
480 | */ | 471 | */ |
481 | if ((curr != snap || (curr & 0x1) == 0) && | 472 | if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) { |
482 | (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) { | ||
483 | rdp->dynticks_fqs++; | 473 | rdp->dynticks_fqs++; |
484 | return 1; | 474 | return 1; |
485 | } | 475 | } |
@@ -908,6 +898,12 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) | |||
908 | unsigned long gp_duration; | 898 | unsigned long gp_duration; |
909 | 899 | ||
910 | WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); | 900 | WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); |
901 | |||
902 | /* | ||
903 | * Ensure that all grace-period and pre-grace-period activity | ||
904 | * is seen before the assignment to rsp->completed. | ||
905 | */ | ||
906 | smp_mb(); /* See above block comment. */ | ||
911 | gp_duration = jiffies - rsp->gp_start; | 907 | gp_duration = jiffies - rsp->gp_start; |
912 | if (gp_duration > rsp->gp_max) | 908 | if (gp_duration > rsp->gp_max) |
913 | rsp->gp_max = gp_duration; | 909 | rsp->gp_max = gp_duration; |
@@ -1455,25 +1451,11 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1455 | */ | 1451 | */ |
1456 | static void rcu_process_callbacks(void) | 1452 | static void rcu_process_callbacks(void) |
1457 | { | 1453 | { |
1458 | /* | ||
1459 | * Memory references from any prior RCU read-side critical sections | ||
1460 | * executed by the interrupted code must be seen before any RCU | ||
1461 | * grace-period manipulations below. | ||
1462 | */ | ||
1463 | smp_mb(); /* See above block comment. */ | ||
1464 | |||
1465 | __rcu_process_callbacks(&rcu_sched_state, | 1454 | __rcu_process_callbacks(&rcu_sched_state, |
1466 | &__get_cpu_var(rcu_sched_data)); | 1455 | &__get_cpu_var(rcu_sched_data)); |
1467 | __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); | 1456 | __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); |
1468 | rcu_preempt_process_callbacks(); | 1457 | rcu_preempt_process_callbacks(); |
1469 | 1458 | ||
1470 | /* | ||
1471 | * Memory references from any later RCU read-side critical sections | ||
1472 | * executed by the interrupted code must be seen after any RCU | ||
1473 | * grace-period manipulations above. | ||
1474 | */ | ||
1475 | smp_mb(); /* See above block comment. */ | ||
1476 | |||
1477 | /* If we are last CPU on way to dyntick-idle mode, accelerate it. */ | 1459 | /* If we are last CPU on way to dyntick-idle mode, accelerate it. */ |
1478 | rcu_needs_cpu_flush(); | 1460 | rcu_needs_cpu_flush(); |
1479 | } | 1461 | } |
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 257664815d5d..93d4a1c2e88b 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -84,11 +84,9 @@ | |||
84 | * Dynticks per-CPU state. | 84 | * Dynticks per-CPU state. |
85 | */ | 85 | */ |
86 | struct rcu_dynticks { | 86 | struct rcu_dynticks { |
87 | int dynticks_nesting; /* Track nesting level, sort of. */ | 87 | int dynticks_nesting; /* Track irq/process nesting level. */ |
88 | int dynticks; /* Even value for dynticks-idle, else odd. */ | 88 | int dynticks_nmi_nesting; /* Track NMI nesting level. */ |
89 | int dynticks_nmi; /* Even value for either dynticks-idle or */ | 89 | atomic_t dynticks; /* Even value for dynticks-idle, else odd. */ |
90 | /* not in nmi handler, else odd. So this */ | ||
91 | /* remains even for nmi from irq handler. */ | ||
92 | }; | 90 | }; |
93 | 91 | ||
94 | /* RCU's kthread states for tracing. */ | 92 | /* RCU's kthread states for tracing. */ |
@@ -284,7 +282,6 @@ struct rcu_data { | |||
284 | /* 3) dynticks interface. */ | 282 | /* 3) dynticks interface. */ |
285 | struct rcu_dynticks *dynticks; /* Shared per-CPU dynticks state. */ | 283 | struct rcu_dynticks *dynticks; /* Shared per-CPU dynticks state. */ |
286 | int dynticks_snap; /* Per-GP tracking for dynticks. */ | 284 | int dynticks_snap; /* Per-GP tracking for dynticks. */ |
287 | int dynticks_nmi_snap; /* Per-GP tracking for dynticks_nmi. */ | ||
288 | #endif /* #ifdef CONFIG_NO_HZ */ | 285 | #endif /* #ifdef CONFIG_NO_HZ */ |
289 | 286 | ||
290 | /* 4) reasons this CPU needed to be kicked by force_quiescent_state */ | 287 | /* 4) reasons this CPU needed to be kicked by force_quiescent_state */ |
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 3f6559a5f5cd..ed339702481d 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -1520,7 +1520,6 @@ int rcu_needs_cpu(int cpu) | |||
1520 | { | 1520 | { |
1521 | int c = 0; | 1521 | int c = 0; |
1522 | int snap; | 1522 | int snap; |
1523 | int snap_nmi; | ||
1524 | int thatcpu; | 1523 | int thatcpu; |
1525 | 1524 | ||
1526 | /* Check for being in the holdoff period. */ | 1525 | /* Check for being in the holdoff period. */ |
@@ -1531,10 +1530,10 @@ int rcu_needs_cpu(int cpu) | |||
1531 | for_each_online_cpu(thatcpu) { | 1530 | for_each_online_cpu(thatcpu) { |
1532 | if (thatcpu == cpu) | 1531 | if (thatcpu == cpu) |
1533 | continue; | 1532 | continue; |
1534 | snap = per_cpu(rcu_dynticks, thatcpu).dynticks; | 1533 | snap = atomic_add_return(0, &per_cpu(rcu_dynticks, |
1535 | snap_nmi = per_cpu(rcu_dynticks, thatcpu).dynticks_nmi; | 1534 | thatcpu).dynticks); |
1536 | smp_mb(); /* Order sampling of snap with end of grace period. */ | 1535 | smp_mb(); /* Order sampling of snap with end of grace period. */ |
1537 | if (((snap & 0x1) != 0) || ((snap_nmi & 0x1) != 0)) { | 1536 | if ((snap & 0x1) != 0) { |
1538 | per_cpu(rcu_dyntick_drain, cpu) = 0; | 1537 | per_cpu(rcu_dyntick_drain, cpu) = 0; |
1539 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; | 1538 | per_cpu(rcu_dyntick_holdoff, cpu) = jiffies - 1; |
1540 | return rcu_needs_cpu_quick_check(cpu); | 1539 | return rcu_needs_cpu_quick_check(cpu); |
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index aa0fd72b4bc7..9678cc3650f5 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c | |||
@@ -69,10 +69,10 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) | |||
69 | rdp->passed_quiesc, rdp->passed_quiesc_completed, | 69 | rdp->passed_quiesc, rdp->passed_quiesc_completed, |
70 | rdp->qs_pending); | 70 | rdp->qs_pending); |
71 | #ifdef CONFIG_NO_HZ | 71 | #ifdef CONFIG_NO_HZ |
72 | seq_printf(m, " dt=%d/%d dn=%d df=%lu", | 72 | seq_printf(m, " dt=%d/%d/%d df=%lu", |
73 | rdp->dynticks->dynticks, | 73 | atomic_read(&rdp->dynticks->dynticks), |
74 | rdp->dynticks->dynticks_nesting, | 74 | rdp->dynticks->dynticks_nesting, |
75 | rdp->dynticks->dynticks_nmi, | 75 | rdp->dynticks->dynticks_nmi_nesting, |
76 | rdp->dynticks_fqs); | 76 | rdp->dynticks_fqs); |
77 | #endif /* #ifdef CONFIG_NO_HZ */ | 77 | #endif /* #ifdef CONFIG_NO_HZ */ |
78 | seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); | 78 | seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi); |
@@ -141,9 +141,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) | |||
141 | rdp->qs_pending); | 141 | rdp->qs_pending); |
142 | #ifdef CONFIG_NO_HZ | 142 | #ifdef CONFIG_NO_HZ |
143 | seq_printf(m, ",%d,%d,%d,%lu", | 143 | seq_printf(m, ",%d,%d,%d,%lu", |
144 | rdp->dynticks->dynticks, | 144 | atomic_read(&rdp->dynticks->dynticks), |
145 | rdp->dynticks->dynticks_nesting, | 145 | rdp->dynticks->dynticks_nesting, |
146 | rdp->dynticks->dynticks_nmi, | 146 | rdp->dynticks->dynticks_nmi_nesting, |
147 | rdp->dynticks_fqs); | 147 | rdp->dynticks_fqs); |
148 | #endif /* #ifdef CONFIG_NO_HZ */ | 148 | #endif /* #ifdef CONFIG_NO_HZ */ |
149 | seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); | 149 | seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi); |
@@ -167,7 +167,7 @@ static int show_rcudata_csv(struct seq_file *m, void *unused) | |||
167 | { | 167 | { |
168 | seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\","); | 168 | seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\","); |
169 | #ifdef CONFIG_NO_HZ | 169 | #ifdef CONFIG_NO_HZ |
170 | seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\","); | 170 | seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\","); |
171 | #endif /* #ifdef CONFIG_NO_HZ */ | 171 | #endif /* #ifdef CONFIG_NO_HZ */ |
172 | seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n"); | 172 | seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n"); |
173 | #ifdef CONFIG_TREE_PREEMPT_RCU | 173 | #ifdef CONFIG_TREE_PREEMPT_RCU |