diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-05-12 04:08:07 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-05-19 17:25:29 -0400 |
commit | 80d02085d99039b3b7f3a73c8896226b0cb1ba07 (patch) | |
tree | c310902423ecb00effadcb59c60cbf118d4037cb /kernel/rcutree.c | |
parent | 11c476f31a0fabc6e604da5b09a6590b57c3fb20 (diff) |
Revert "rcu: Decrease memory-barrier usage based on semi-formal proof"
This reverts commit e59fb3120becfb36b22ddb8bd27d065d3cdca499.
This reversion was due to (extreme) boot-time slowdowns on SPARC seen by
Yinghai Lu and on x86 by Ingo
.
This is a non-trivial reversion due to intervening commits.
Conflicts:
Documentation/RCU/trace.txt
kernel/rcutree.c
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r-- | kernel/rcutree.c | 130 |
1 files changed, 74 insertions, 56 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 5616b17e4a22..e486f7c3ffb8 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch); | |||
162 | #ifdef CONFIG_NO_HZ | 162 | #ifdef CONFIG_NO_HZ |
163 | DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { | 163 | DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = { |
164 | .dynticks_nesting = 1, | 164 | .dynticks_nesting = 1, |
165 | .dynticks = ATOMIC_INIT(1), | 165 | .dynticks = 1, |
166 | }; | 166 | }; |
167 | #endif /* #ifdef CONFIG_NO_HZ */ | 167 | #endif /* #ifdef CONFIG_NO_HZ */ |
168 | 168 | ||
@@ -321,25 +321,13 @@ void rcu_enter_nohz(void) | |||
321 | unsigned long flags; | 321 | unsigned long flags; |
322 | struct rcu_dynticks *rdtp; | 322 | struct rcu_dynticks *rdtp; |
323 | 323 | ||
324 | smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ | ||
324 | local_irq_save(flags); | 325 | local_irq_save(flags); |
325 | rdtp = &__get_cpu_var(rcu_dynticks); | 326 | rdtp = &__get_cpu_var(rcu_dynticks); |
326 | if (--rdtp->dynticks_nesting) { | 327 | rdtp->dynticks++; |
327 | local_irq_restore(flags); | 328 | rdtp->dynticks_nesting--; |
328 | return; | 329 | WARN_ON_ONCE(rdtp->dynticks & 0x1); |
329 | } | ||
330 | /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ | ||
331 | smp_mb__before_atomic_inc(); /* See above. */ | ||
332 | atomic_inc(&rdtp->dynticks); | ||
333 | smp_mb__after_atomic_inc(); /* Force ordering with next sojourn. */ | ||
334 | WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); | ||
335 | local_irq_restore(flags); | 330 | local_irq_restore(flags); |
336 | |||
337 | /* If the interrupt queued a callback, get out of dyntick mode. */ | ||
338 | if (in_irq() && | ||
339 | (__get_cpu_var(rcu_sched_data).nxtlist || | ||
340 | __get_cpu_var(rcu_bh_data).nxtlist || | ||
341 | rcu_preempt_needs_cpu(smp_processor_id()))) | ||
342 | set_need_resched(); | ||
343 | } | 331 | } |
344 | 332 | ||
345 | /* | 333 | /* |
@@ -355,16 +343,11 @@ void rcu_exit_nohz(void) | |||
355 | 343 | ||
356 | local_irq_save(flags); | 344 | local_irq_save(flags); |
357 | rdtp = &__get_cpu_var(rcu_dynticks); | 345 | rdtp = &__get_cpu_var(rcu_dynticks); |
358 | if (rdtp->dynticks_nesting++) { | 346 | rdtp->dynticks++; |
359 | local_irq_restore(flags); | 347 | rdtp->dynticks_nesting++; |
360 | return; | 348 | WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); |
361 | } | ||
362 | smp_mb__before_atomic_inc(); /* Force ordering w/previous sojourn. */ | ||
363 | atomic_inc(&rdtp->dynticks); | ||
364 | /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ | ||
365 | smp_mb__after_atomic_inc(); /* See above. */ | ||
366 | WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); | ||
367 | local_irq_restore(flags); | 349 | local_irq_restore(flags); |
350 | smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ | ||
368 | } | 351 | } |
369 | 352 | ||
370 | /** | 353 | /** |
@@ -378,15 +361,11 @@ void rcu_nmi_enter(void) | |||
378 | { | 361 | { |
379 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); | 362 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); |
380 | 363 | ||
381 | if (rdtp->dynticks_nmi_nesting == 0 && | 364 | if (rdtp->dynticks & 0x1) |
382 | (atomic_read(&rdtp->dynticks) & 0x1)) | ||
383 | return; | 365 | return; |
384 | rdtp->dynticks_nmi_nesting++; | 366 | rdtp->dynticks_nmi++; |
385 | smp_mb__before_atomic_inc(); /* Force delay from prior write. */ | 367 | WARN_ON_ONCE(!(rdtp->dynticks_nmi & 0x1)); |
386 | atomic_inc(&rdtp->dynticks); | 368 | smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ |
387 | /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ | ||
388 | smp_mb__after_atomic_inc(); /* See above. */ | ||
389 | WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); | ||
390 | } | 369 | } |
391 | 370 | ||
392 | /** | 371 | /** |
@@ -400,14 +379,11 @@ void rcu_nmi_exit(void) | |||
400 | { | 379 | { |
401 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); | 380 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); |
402 | 381 | ||
403 | if (rdtp->dynticks_nmi_nesting == 0 || | 382 | if (rdtp->dynticks & 0x1) |
404 | --rdtp->dynticks_nmi_nesting != 0) | ||
405 | return; | 383 | return; |
406 | /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ | 384 | smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ |
407 | smp_mb__before_atomic_inc(); /* See above. */ | 385 | rdtp->dynticks_nmi++; |
408 | atomic_inc(&rdtp->dynticks); | 386 | WARN_ON_ONCE(rdtp->dynticks_nmi & 0x1); |
409 | smp_mb__after_atomic_inc(); /* Force delay to next write. */ | ||
410 | WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1); | ||
411 | } | 387 | } |
412 | 388 | ||
413 | /** | 389 | /** |
@@ -418,7 +394,13 @@ void rcu_nmi_exit(void) | |||
418 | */ | 394 | */ |
419 | void rcu_irq_enter(void) | 395 | void rcu_irq_enter(void) |
420 | { | 396 | { |
421 | rcu_exit_nohz(); | 397 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); |
398 | |||
399 | if (rdtp->dynticks_nesting++) | ||
400 | return; | ||
401 | rdtp->dynticks++; | ||
402 | WARN_ON_ONCE(!(rdtp->dynticks & 0x1)); | ||
403 | smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ | ||
422 | } | 404 | } |
423 | 405 | ||
424 | /** | 406 | /** |
@@ -430,7 +412,18 @@ void rcu_irq_enter(void) | |||
430 | */ | 412 | */ |
431 | void rcu_irq_exit(void) | 413 | void rcu_irq_exit(void) |
432 | { | 414 | { |
433 | rcu_enter_nohz(); | 415 | struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks); |
416 | |||
417 | if (--rdtp->dynticks_nesting) | ||
418 | return; | ||
419 | smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ | ||
420 | rdtp->dynticks++; | ||
421 | WARN_ON_ONCE(rdtp->dynticks & 0x1); | ||
422 | |||
423 | /* If the interrupt queued a callback, get out of dyntick mode. */ | ||
424 | if (__this_cpu_read(rcu_sched_data.nxtlist) || | ||
425 | __this_cpu_read(rcu_bh_data.nxtlist)) | ||
426 | set_need_resched(); | ||
434 | } | 427 | } |
435 | 428 | ||
436 | #ifdef CONFIG_SMP | 429 | #ifdef CONFIG_SMP |
@@ -442,8 +435,19 @@ void rcu_irq_exit(void) | |||
442 | */ | 435 | */ |
443 | static int dyntick_save_progress_counter(struct rcu_data *rdp) | 436 | static int dyntick_save_progress_counter(struct rcu_data *rdp) |
444 | { | 437 | { |
445 | rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks); | 438 | int ret; |
446 | return 0; | 439 | int snap; |
440 | int snap_nmi; | ||
441 | |||
442 | snap = rdp->dynticks->dynticks; | ||
443 | snap_nmi = rdp->dynticks->dynticks_nmi; | ||
444 | smp_mb(); /* Order sampling of snap with end of grace period. */ | ||
445 | rdp->dynticks_snap = snap; | ||
446 | rdp->dynticks_nmi_snap = snap_nmi; | ||
447 | ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0); | ||
448 | if (ret) | ||
449 | rdp->dynticks_fqs++; | ||
450 | return ret; | ||
447 | } | 451 | } |
448 | 452 | ||
449 | /* | 453 | /* |
@@ -454,11 +458,16 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp) | |||
454 | */ | 458 | */ |
455 | static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | 459 | static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) |
456 | { | 460 | { |
457 | unsigned long curr; | 461 | long curr; |
458 | unsigned long snap; | 462 | long curr_nmi; |
463 | long snap; | ||
464 | long snap_nmi; | ||
459 | 465 | ||
460 | curr = (unsigned long)atomic_add_return(0, &rdp->dynticks->dynticks); | 466 | curr = rdp->dynticks->dynticks; |
461 | snap = (unsigned long)rdp->dynticks_snap; | 467 | snap = rdp->dynticks_snap; |
468 | curr_nmi = rdp->dynticks->dynticks_nmi; | ||
469 | snap_nmi = rdp->dynticks_nmi_snap; | ||
470 | smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ | ||
462 | 471 | ||
463 | /* | 472 | /* |
464 | * If the CPU passed through or entered a dynticks idle phase with | 473 | * If the CPU passed through or entered a dynticks idle phase with |
@@ -468,7 +477,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
468 | * read-side critical section that started before the beginning | 477 | * read-side critical section that started before the beginning |
469 | * of the current RCU grace period. | 478 | * of the current RCU grace period. |
470 | */ | 479 | */ |
471 | if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) { | 480 | if ((curr != snap || (curr & 0x1) == 0) && |
481 | (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) { | ||
472 | rdp->dynticks_fqs++; | 482 | rdp->dynticks_fqs++; |
473 | return 1; | 483 | return 1; |
474 | } | 484 | } |
@@ -897,12 +907,6 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) | |||
897 | unsigned long gp_duration; | 907 | unsigned long gp_duration; |
898 | 908 | ||
899 | WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); | 909 | WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); |
900 | |||
901 | /* | ||
902 | * Ensure that all grace-period and pre-grace-period activity | ||
903 | * is seen before the assignment to rsp->completed. | ||
904 | */ | ||
905 | smp_mb(); /* See above block comment. */ | ||
906 | gp_duration = jiffies - rsp->gp_start; | 910 | gp_duration = jiffies - rsp->gp_start; |
907 | if (gp_duration > rsp->gp_max) | 911 | if (gp_duration > rsp->gp_max) |
908 | rsp->gp_max = gp_duration; | 912 | rsp->gp_max = gp_duration; |
@@ -1450,11 +1454,25 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1450 | */ | 1454 | */ |
1451 | static void rcu_process_callbacks(void) | 1455 | static void rcu_process_callbacks(void) |
1452 | { | 1456 | { |
1457 | /* | ||
1458 | * Memory references from any prior RCU read-side critical sections | ||
1459 | * executed by the interrupted code must be seen before any RCU | ||
1460 | * grace-period manipulations below. | ||
1461 | */ | ||
1462 | smp_mb(); /* See above block comment. */ | ||
1463 | |||
1453 | __rcu_process_callbacks(&rcu_sched_state, | 1464 | __rcu_process_callbacks(&rcu_sched_state, |
1454 | &__get_cpu_var(rcu_sched_data)); | 1465 | &__get_cpu_var(rcu_sched_data)); |
1455 | __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); | 1466 | __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); |
1456 | rcu_preempt_process_callbacks(); | 1467 | rcu_preempt_process_callbacks(); |
1457 | 1468 | ||
1469 | /* | ||
1470 | * Memory references from any later RCU read-side critical sections | ||
1471 | * executed by the interrupted code must be seen after any RCU | ||
1472 | * grace-period manipulations above. | ||
1473 | */ | ||
1474 | smp_mb(); /* See above block comment. */ | ||
1475 | |||
1458 | /* If we are last CPU on way to dyntick-idle mode, accelerate it. */ | 1476 | /* If we are last CPU on way to dyntick-idle mode, accelerate it. */ |
1459 | rcu_needs_cpu_flush(); | 1477 | rcu_needs_cpu_flush(); |
1460 | } | 1478 | } |