Commit f511fc624642f0bb8cf65aaa28979737514d4746
Committed by
Paul E. McKenney
1 parent
79b9a75fb7
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
rcu: Ensure that RCU_FAST_NO_HZ timers expire on correct CPU
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 mod_timer_pinned(), as suggested by Peter Zijlstra, to ensure that the timer is actually posted on the running CPU. Reported-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Showing 1 changed file with 8 additions and 5 deletions Side-by-side Diff
kernel/rcutree_plugin.h
... | ... | @@ -2110,6 +2110,8 @@ |
2110 | 2110 | */ |
2111 | 2111 | static void rcu_prepare_for_idle(int cpu) |
2112 | 2112 | { |
2113 | + struct timer_list *tp; | |
2114 | + | |
2113 | 2115 | /* |
2114 | 2116 | * If this is an idle re-entry, for example, due to use of |
2115 | 2117 | * RCU_NONIDLE() or the new idle-loop tracing API within the idle |
... | ... | @@ -2121,9 +2123,10 @@ |
2121 | 2123 | if (!per_cpu(rcu_idle_first_pass, cpu) && |
2122 | 2124 | (per_cpu(rcu_nonlazy_posted, cpu) == |
2123 | 2125 | per_cpu(rcu_nonlazy_posted_snap, cpu))) { |
2124 | - if (rcu_cpu_has_callbacks(cpu)) | |
2125 | - mod_timer(&per_cpu(rcu_idle_gp_timer, cpu), | |
2126 | - per_cpu(rcu_idle_gp_timer_expires, cpu)); | |
2126 | + if (rcu_cpu_has_callbacks(cpu)) { | |
2127 | + tp = &per_cpu(rcu_idle_gp_timer, cpu); | |
2128 | + mod_timer_pinned(tp, per_cpu(rcu_idle_gp_timer_expires, cpu)); | |
2129 | + } | |
2127 | 2130 | return; |
2128 | 2131 | } |
2129 | 2132 | per_cpu(rcu_idle_first_pass, cpu) = 0; |
... | ... | @@ -2167,8 +2170,8 @@ |
2167 | 2170 | else |
2168 | 2171 | per_cpu(rcu_idle_gp_timer_expires, cpu) = |
2169 | 2172 | jiffies + RCU_IDLE_LAZY_GP_DELAY; |
2170 | - mod_timer(&per_cpu(rcu_idle_gp_timer, cpu), | |
2171 | - per_cpu(rcu_idle_gp_timer_expires, cpu)); | |
2173 | + tp = &per_cpu(rcu_idle_gp_timer, cpu); | |
2174 | + mod_timer_pinned(tp, per_cpu(rcu_idle_gp_timer_expires, cpu)); | |
2172 | 2175 | per_cpu(rcu_nonlazy_posted_snap, cpu) = |
2173 | 2176 | per_cpu(rcu_nonlazy_posted, cpu); |
2174 | 2177 | return; /* Nothing more to do immediately. */ |