summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-08-14 19:24:26 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-09-23 12:18:13 -0400
commit9261dd0da6c6432f08670719069449c6efe4f7a9 (patch)
treeb8c95dd0e4751e3069e9263d6f46b86251d5dc35
parentbb311eccbdab974639263060b8452bf304af0b0c (diff)
rcu: Add tracing for rcuo no-CBs CPU wakeup handshake
Lost wakeups from call_rcu() to the rcuo kthreads can result in hangs that are difficult to diagnose. This commit therefore adds tracing to help pin down the cause of these hangs. Reported-by: Clark Williams <williams@redhat.com> Reported-by: Carsten Emde <C.Emde@osadl.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> [ paulmck: Add const per kbuild test robot's advice. ]
-rw-r--r--include/trace/events/rcu.h37
-rw-r--r--kernel/rcutree_plugin.h14
2 files changed, 50 insertions, 1 deletions
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index 98466c618ebc..4301cd9e3ee5 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -172,6 +172,42 @@ TRACE_EVENT(rcu_grace_period_init,
172); 172);
173 173
174/* 174/*
175 * Tracepoint for RCU no-CBs CPU callback handoffs. This event is intended
176 * to assist debugging of these handoffs.
177 *
178 * The first argument is the name of the RCU flavor, and the second is
179 * the number of the offloaded CPU are extracted. The third and final
180 * argument is a string as follows:
181 *
182 * "WakeEmpty": Wake rcuo kthread, first CB to empty list.
183 * "WakeOvf": Wake rcuo kthread, CB list is huge.
184 * "WakeNot": Don't wake rcuo kthread.
185 * "WakeNotPoll": Don't wake rcuo kthread because it is polling.
186 * "WokeEmpty": rcuo kthread woke to find empty list.
187 * "WokeNonEmpty": rcuo kthread woke to find non-empty list.
188 */
189TRACE_EVENT(rcu_nocb_wake,
190
191 TP_PROTO(const char *rcuname, int cpu, const char *reason),
192
193 TP_ARGS(rcuname, cpu, reason),
194
195 TP_STRUCT__entry(
196 __field(const char *, rcuname)
197 __field(int, cpu)
198 __field(const char *, reason)
199 ),
200
201 TP_fast_assign(
202 __entry->rcuname = rcuname;
203 __entry->cpu = cpu;
204 __entry->reason = reason;
205 ),
206
207 TP_printk("%s %d %s", __entry->rcuname, __entry->cpu, __entry->reason)
208);
209
210/*
175 * Tracepoint for tasks blocking within preemptible-RCU read-side 211 * Tracepoint for tasks blocking within preemptible-RCU read-side
176 * critical sections. Track the type of RCU (which one day might 212 * critical sections. Track the type of RCU (which one day might
177 * include SRCU), the grace-period number that the task is blocking 213 * include SRCU), the grace-period number that the task is blocking
@@ -667,6 +703,7 @@ TRACE_EVENT(rcu_barrier,
667#define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \ 703#define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \
668 level, grplo, grphi, event) \ 704 level, grplo, grphi, event) \
669 do { } while (0) 705 do { } while (0)
706#define trace_rcu_nocb_wake(rcuname, cpu, reason) do { } while (0)
670#define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) 707#define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0)
671#define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) 708#define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0)
672#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \ 709#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 130c97b027f2..f4ed24b18e77 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -2108,15 +2108,22 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp,
2108 2108
2109 /* If we are not being polled and there is a kthread, awaken it ... */ 2109 /* If we are not being polled and there is a kthread, awaken it ... */
2110 t = ACCESS_ONCE(rdp->nocb_kthread); 2110 t = ACCESS_ONCE(rdp->nocb_kthread);
2111 if (rcu_nocb_poll | !t) 2111 if (rcu_nocb_poll | !t) {
2112 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
2113 TPS("WakeNotPoll"));
2112 return; 2114 return;
2115 }
2113 len = atomic_long_read(&rdp->nocb_q_count); 2116 len = atomic_long_read(&rdp->nocb_q_count);
2114 if (old_rhpp == &rdp->nocb_head) { 2117 if (old_rhpp == &rdp->nocb_head) {
2115 wake_up(&rdp->nocb_wq); /* ... only if queue was empty ... */ 2118 wake_up(&rdp->nocb_wq); /* ... only if queue was empty ... */
2116 rdp->qlen_last_fqs_check = 0; 2119 rdp->qlen_last_fqs_check = 0;
2120 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeEmpty"));
2117 } else if (len > rdp->qlen_last_fqs_check + qhimark) { 2121 } else if (len > rdp->qlen_last_fqs_check + qhimark) {
2118 wake_up_process(t); /* ... or if many callbacks queued. */ 2122 wake_up_process(t); /* ... or if many callbacks queued. */
2119 rdp->qlen_last_fqs_check = LONG_MAX / 2; 2123 rdp->qlen_last_fqs_check = LONG_MAX / 2;
2124 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeOvf"));
2125 } else {
2126 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeNot"));
2120 } 2127 }
2121 return; 2128 return;
2122} 2129}
@@ -2233,10 +2240,15 @@ static int rcu_nocb_kthread(void *arg)
2233 wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head); 2240 wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head);
2234 list = ACCESS_ONCE(rdp->nocb_head); 2241 list = ACCESS_ONCE(rdp->nocb_head);
2235 if (!list) { 2242 if (!list) {
2243 if (!rcu_nocb_poll)
2244 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
2245 TPS("WokeEmpty"));
2236 schedule_timeout_interruptible(1); 2246 schedule_timeout_interruptible(1);
2237 flush_signals(current); 2247 flush_signals(current);
2238 continue; 2248 continue;
2239 } 2249 }
2250 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
2251 TPS("WokeNonEmpty"));
2240 2252
2241 /* 2253 /*
2242 * Extract queued callbacks, update counts, and wait 2254 * Extract queued callbacks, update counts, and wait