[PATCH RFC tip/core/rcu 0/4] Updates to RCU_FAST_NO_HZ

April 23rd, 2012 - 12:20 pm ET by Paul E. McKenney | Report spam
Hello!

This series covers enhancements to RCU_FAST_NO_HZ intended for v3.4-rc2.
The individual commits are as follows:

1. Add tracing to rcu_cleanup_after_idle().
2. Switch from hrtimer to normal timers to reduce overhead.
3. Upgrade RCU_FAST_NO_HZ state machine to better account for
brief pauses out of idle, which can happen due to power-management
actions, Steven Rostedt's new RCU-idle-capable tracing macros,
or my RCU_NONIDLE() macro.
4. Use add_timer_on() to avoid timer migration.

Thanx, Paul


b/include/trace/events/rcu.h | 1
b/kernel/rcutree.c | 2
b/kernel/rcutree.h | 1
b/kernel/rcutree_plugin.h | 1
kernel/rcutree_plugin.h | 112 ++++++++++++++++++++++++++++
5 files changed, 80 insertions(+), 37 deletions(-)

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
email Follow the discussionReplies 10 repliesReplies Make a reply

Replies

#1 Paul E. McKenney
April 23rd, 2012 - 12:20 pm ET | Report spam
From: "Paul E. McKenney"

Timers are subject to migration, which can lead to the following
system-hang scenario when CONFIG_RCU_FAST_NO_HZ=y:

1. CPU 0 executes synchronize_rcu(), which posts an RCU callback.

2. CPU 0 then goes idle. It cannot immediately invoke the callback,
but there is nothing RCU needs from ti, so it enters dyntick-idle
mode after posting a timer.

3. The timer gets migrated to CPU 1.

4. CPU 0 never wakes up, so the synchronize_rcu() never returns, so
the system hangs.

This commit fixes this problem by using add_timer_on() to ensure that
the timer remains on the CPU that posted it.

Reported-by: Dipankar Sarma
Signed-off-by: Paul E. McKenney
Signed-off-by: Paul E. McKenney

kernel/rcutree_plugin.h | 15 ++++++++++--
1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 50c1797..90b3de5 100644
a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -2109,6 +2109,8 @@ static void rcu_cleanup_after_idle(int cpu)
*/
static void rcu_prepare_for_idle(int cpu)
{
+ struct timer_list *tp;
+
/*
* If this is an idle re-entry, for example, due to use of
* RCU_NONIDLE() or the new idle-loop tracing API within the idle
@@ -2120,9 +2122,11 @@ static void rcu_prepare_for_idle(int cpu)
if (!per_cpu(rcu_idle_first_pass, cpu) &&
(per_cpu(rcu_nonlazy_posted, cpu) = per_cpu(rcu_nonlazy_posted_snap, cpu))) {
- if (rcu_cpu_has_callbacks(cpu))
- mod_timer(&per_cpu(rcu_idle_gp_timer, cpu),
- per_cpu(rcu_idle_gp_timer_expires, cpu));
+ if (rcu_cpu_has_callbacks(cpu)) {
+ tp = &per_cpu(rcu_idle_gp_timer, cpu);
+ tp->expires = per_cpu(rcu_idle_gp_timer_expires, cpu);
+ add_timer_on(tp, cpu);
+ }
return;
}
per_cpu(rcu_idle_first_pass, cpu) = 0;
@@ -2166,8 +2170,9 @@ static void rcu_prepare_for_idle(int cpu)
else
per_cpu(rcu_idle_gp_timer_expires, cpu) jiffies + RCU_IDLE_LAZY_GP_DELAY;
- mod_timer(&per_cpu(rcu_idle_gp_timer, cpu),
- per_cpu(rcu_idle_gp_timer_expires, cpu));
+ tp = &per_cpu(rcu_idle_gp_timer, cpu);
+ tp->expires = per_cpu(rcu_idle_gp_timer_expires, cpu);
+ add_timer_on(tp, cpu);
per_cpu(rcu_nonlazy_posted_snap, cpu) per_cpu(rcu_nonlazy_posted, cpu);
return; /* Nothing more to do immediately. */
1.7.8

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Similar topics