diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2011-06-25 09:36:56 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-09-29 00:38:21 -0400 |
commit | d4c08f2ac311a360230eef7e5395b0ec8d8f0670 (patch) | |
tree | 06e425b8153e076fbe43b037cf4497ac50afddb7 | |
parent | 965a002b4f1a458c5dcb334ec29f48a0046faa25 (diff) |
rcu: Add grace-period, quiescent-state, and call_rcu trace events
Add trace events to record grace-period start and end, quiescent states,
CPUs noticing grace-period start and end, grace-period initialization,
call_rcu() invocation, tasks blocking in RCU read-side critical sections,
tasks exiting those same critical sections, force_quiescent_state()
detection of dyntick-idle and offline CPUs, CPUs entering and leaving
dyntick-idle mode (except from NMIs), CPUs coming online and going
offline, and CPUs being kicked for staying in dyntick-idle mode for too
long (as in many weeks, even on 32-bit systems).
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
rcu: Add the rcu flavor to callback trace events
The earlier trace events for registering RCU callbacks and for invoking
them did not include the RCU flavor (rcu_bh, rcu_preempt, or rcu_sched).
This commit adds the RCU flavor to those trace events.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r-- | include/trace/events/rcu.h | 345 | ||||
-rw-r--r-- | kernel/rcu.h | 6 | ||||
-rw-r--r-- | kernel/rcutiny.c | 4 | ||||
-rw-r--r-- | kernel/rcutree.c | 45 | ||||
-rw-r--r-- | kernel/rcutree.h | 1 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 22 |
6 files changed, 399 insertions, 24 deletions
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h index ac52aba00a3e..669fbd62ec25 100644 --- a/include/trace/events/rcu.h +++ b/include/trace/events/rcu.h | |||
@@ -24,7 +24,7 @@ TRACE_EVENT(rcu_utilization, | |||
24 | TP_ARGS(s), | 24 | TP_ARGS(s), |
25 | 25 | ||
26 | TP_STRUCT__entry( | 26 | TP_STRUCT__entry( |
27 | __field(char *, s) | 27 | __field(char *, s) |
28 | ), | 28 | ), |
29 | 29 | ||
30 | TP_fast_assign( | 30 | TP_fast_assign( |
@@ -34,6 +34,297 @@ TRACE_EVENT(rcu_utilization, | |||
34 | TP_printk("%s", __entry->s) | 34 | TP_printk("%s", __entry->s) |
35 | ); | 35 | ); |
36 | 36 | ||
37 | #ifdef CONFIG_RCU_TRACE | ||
38 | |||
39 | #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) | ||
40 | |||
41 | /* | ||
42 | * Tracepoint for grace-period events: starting and ending a grace | ||
43 | * period ("start" and "end", respectively), a CPU noting the start | ||
44 | * of a new grace period or the end of an old grace period ("cpustart" | ||
45 | * and "cpuend", respectively), a CPU passing through a quiescent | ||
46 | * state ("cpuqs"), a CPU coming online or going offline ("cpuonl" | ||
47 | * and "cpuofl", respectively), and a CPU being kicked for being too | ||
48 | * long in dyntick-idle mode ("kick"). | ||
49 | */ | ||
50 | TRACE_EVENT(rcu_grace_period, | ||
51 | |||
52 | TP_PROTO(char *rcuname, unsigned long gpnum, char *gpevent), | ||
53 | |||
54 | TP_ARGS(rcuname, gpnum, gpevent), | ||
55 | |||
56 | TP_STRUCT__entry( | ||
57 | __field(char *, rcuname) | ||
58 | __field(unsigned long, gpnum) | ||
59 | __field(char *, gpevent) | ||
60 | ), | ||
61 | |||
62 | TP_fast_assign( | ||
63 | __entry->rcuname = rcuname; | ||
64 | __entry->gpnum = gpnum; | ||
65 | __entry->gpevent = gpevent; | ||
66 | ), | ||
67 | |||
68 | TP_printk("%s %lu %s", | ||
69 | __entry->rcuname, __entry->gpnum, __entry->gpevent) | ||
70 | ); | ||
71 | |||
72 | /* | ||
73 | * Tracepoint for grace-period-initialization events. These are | ||
74 | * distinguished by the type of RCU, the new grace-period number, the | ||
75 | * rcu_node structure level, the starting and ending CPU covered by the | ||
76 | * rcu_node structure, and the mask of CPUs that will be waited for. | ||
77 | * All but the type of RCU are extracted from the rcu_node structure. | ||
78 | */ | ||
79 | TRACE_EVENT(rcu_grace_period_init, | ||
80 | |||
81 | TP_PROTO(char *rcuname, unsigned long gpnum, u8 level, | ||
82 | int grplo, int grphi, unsigned long qsmask), | ||
83 | |||
84 | TP_ARGS(rcuname, gpnum, level, grplo, grphi, qsmask), | ||
85 | |||
86 | TP_STRUCT__entry( | ||
87 | __field(char *, rcuname) | ||
88 | __field(unsigned long, gpnum) | ||
89 | __field(u8, level) | ||
90 | __field(int, grplo) | ||
91 | __field(int, grphi) | ||
92 | __field(unsigned long, qsmask) | ||
93 | ), | ||
94 | |||
95 | TP_fast_assign( | ||
96 | __entry->rcuname = rcuname; | ||
97 | __entry->gpnum = gpnum; | ||
98 | __entry->level = level; | ||
99 | __entry->grplo = grplo; | ||
100 | __entry->grphi = grphi; | ||
101 | __entry->qsmask = qsmask; | ||
102 | ), | ||
103 | |||
104 | TP_printk("%s %lu %u %d %d %lx", | ||
105 | __entry->rcuname, __entry->gpnum, __entry->level, | ||
106 | __entry->grplo, __entry->grphi, __entry->qsmask) | ||
107 | ); | ||
108 | |||
109 | /* | ||
110 | * Tracepoint for tasks blocking within preemptible-RCU read-side | ||
111 | * critical sections. Track the type of RCU (which one day might | ||
112 | * include SRCU), the grace-period number that the task is blocking | ||
113 | * (the current or the next), and the task's PID. | ||
114 | */ | ||
115 | TRACE_EVENT(rcu_preempt_task, | ||
116 | |||
117 | TP_PROTO(char *rcuname, int pid, unsigned long gpnum), | ||
118 | |||
119 | TP_ARGS(rcuname, pid, gpnum), | ||
120 | |||
121 | TP_STRUCT__entry( | ||
122 | __field(char *, rcuname) | ||
123 | __field(unsigned long, gpnum) | ||
124 | __field(int, pid) | ||
125 | ), | ||
126 | |||
127 | TP_fast_assign( | ||
128 | __entry->rcuname = rcuname; | ||
129 | __entry->gpnum = gpnum; | ||
130 | __entry->pid = pid; | ||
131 | ), | ||
132 | |||
133 | TP_printk("%s %lu %d", | ||
134 | __entry->rcuname, __entry->gpnum, __entry->pid) | ||
135 | ); | ||
136 | |||
137 | /* | ||
138 | * Tracepoint for tasks that blocked within a given preemptible-RCU | ||
139 | * read-side critical section exiting that critical section. Track the | ||
140 | * type of RCU (which one day might include SRCU) and the task's PID. | ||
141 | */ | ||
142 | TRACE_EVENT(rcu_unlock_preempted_task, | ||
143 | |||
144 | TP_PROTO(char *rcuname, unsigned long gpnum, int pid), | ||
145 | |||
146 | TP_ARGS(rcuname, gpnum, pid), | ||
147 | |||
148 | TP_STRUCT__entry( | ||
149 | __field(char *, rcuname) | ||
150 | __field(unsigned long, gpnum) | ||
151 | __field(int, pid) | ||
152 | ), | ||
153 | |||
154 | TP_fast_assign( | ||
155 | __entry->rcuname = rcuname; | ||
156 | __entry->gpnum = gpnum; | ||
157 | __entry->pid = pid; | ||
158 | ), | ||
159 | |||
160 | TP_printk("%s %lu %d", __entry->rcuname, __entry->gpnum, __entry->pid) | ||
161 | ); | ||
162 | |||
163 | /* | ||
164 | * Tracepoint for quiescent-state-reporting events. These are | ||
165 | * distinguished by the type of RCU, the grace-period number, the | ||
166 | * mask of quiescent lower-level entities, the rcu_node structure level, | ||
167 | * the starting and ending CPU covered by the rcu_node structure, and | ||
168 | * whether there are any blocked tasks blocking the current grace period. | ||
169 | * All but the type of RCU are extracted from the rcu_node structure. | ||
170 | */ | ||
171 | TRACE_EVENT(rcu_quiescent_state_report, | ||
172 | |||
173 | TP_PROTO(char *rcuname, unsigned long gpnum, | ||
174 | unsigned long mask, unsigned long qsmask, | ||
175 | u8 level, int grplo, int grphi, int gp_tasks), | ||
176 | |||
177 | TP_ARGS(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks), | ||
178 | |||
179 | TP_STRUCT__entry( | ||
180 | __field(char *, rcuname) | ||
181 | __field(unsigned long, gpnum) | ||
182 | __field(unsigned long, mask) | ||
183 | __field(unsigned long, qsmask) | ||
184 | __field(u8, level) | ||
185 | __field(int, grplo) | ||
186 | __field(int, grphi) | ||
187 | __field(u8, gp_tasks) | ||
188 | ), | ||
189 | |||
190 | TP_fast_assign( | ||
191 | __entry->rcuname = rcuname; | ||
192 | __entry->gpnum = gpnum; | ||
193 | __entry->mask = mask; | ||
194 | __entry->qsmask = qsmask; | ||
195 | __entry->level = level; | ||
196 | __entry->grplo = grplo; | ||
197 | __entry->grphi = grphi; | ||
198 | __entry->gp_tasks = gp_tasks; | ||
199 | ), | ||
200 | |||
201 | TP_printk("%s %lu %lx>%lx %u %d %d %u", | ||
202 | __entry->rcuname, __entry->gpnum, | ||
203 | __entry->mask, __entry->qsmask, __entry->level, | ||
204 | __entry->grplo, __entry->grphi, __entry->gp_tasks) | ||
205 | ); | ||
206 | |||
207 | /* | ||
208 | * Tracepoint for quiescent states detected by force_quiescent_state(). | ||
209 | * These trace events include the type of RCU, the grace-period number | ||
210 | * that was blocked by the CPU, the CPU itself, and the type of quiescent | ||
211 | * state, which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, | ||
212 | * or "kick" when kicking a CPU that has been in dyntick-idle mode for | ||
213 | * too long. | ||
214 | */ | ||
215 | TRACE_EVENT(rcu_fqs, | ||
216 | |||
217 | TP_PROTO(char *rcuname, unsigned long gpnum, int cpu, char *qsevent), | ||
218 | |||
219 | TP_ARGS(rcuname, gpnum, cpu, qsevent), | ||
220 | |||
221 | TP_STRUCT__entry( | ||
222 | __field(char *, rcuname) | ||
223 | __field(unsigned long, gpnum) | ||
224 | __field(int, cpu) | ||
225 | __field(char *, qsevent) | ||
226 | ), | ||
227 | |||
228 | TP_fast_assign( | ||
229 | __entry->rcuname = rcuname; | ||
230 | __entry->gpnum = gpnum; | ||
231 | __entry->cpu = cpu; | ||
232 | __entry->qsevent = qsevent; | ||
233 | ), | ||
234 | |||
235 | TP_printk("%s %lu %d %s", | ||
236 | __entry->rcuname, __entry->gpnum, | ||
237 | __entry->cpu, __entry->qsevent) | ||
238 | ); | ||
239 | |||
240 | #endif /* #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) */ | ||
241 | |||
242 | /* | ||
243 | * Tracepoint for dyntick-idle entry/exit events. These take a string | ||
244 | * as argument: "Start" for entering dyntick-idle mode and "End" for | ||
245 | * leaving it. | ||
246 | */ | ||
247 | TRACE_EVENT(rcu_dyntick, | ||
248 | |||
249 | TP_PROTO(char *polarity), | ||
250 | |||
251 | TP_ARGS(polarity), | ||
252 | |||
253 | TP_STRUCT__entry( | ||
254 | __field(char *, polarity) | ||
255 | ), | ||
256 | |||
257 | TP_fast_assign( | ||
258 | __entry->polarity = polarity; | ||
259 | ), | ||
260 | |||
261 | TP_printk("%s", __entry->polarity) | ||
262 | ); | ||
263 | |||
264 | /* | ||
265 | * Tracepoint for the registration of a single RCU callback function. | ||
266 | * The first argument is the type of RCU, the second argument is | ||
267 | * a pointer to the RCU callback itself, and the third element is the | ||
268 | * new RCU callback queue length for the current CPU. | ||
269 | */ | ||
270 | TRACE_EVENT(rcu_callback, | ||
271 | |||
272 | TP_PROTO(char *rcuname, struct rcu_head *rhp, long qlen), | ||
273 | |||
274 | TP_ARGS(rcuname, rhp, qlen), | ||
275 | |||
276 | TP_STRUCT__entry( | ||
277 | __field(char *, rcuname) | ||
278 | __field(void *, rhp) | ||
279 | __field(void *, func) | ||
280 | __field(long, qlen) | ||
281 | ), | ||
282 | |||
283 | TP_fast_assign( | ||
284 | __entry->rcuname = rcuname; | ||
285 | __entry->rhp = rhp; | ||
286 | __entry->func = rhp->func; | ||
287 | __entry->qlen = qlen; | ||
288 | ), | ||
289 | |||
290 | TP_printk("%s rhp=%p func=%pf %ld", | ||
291 | __entry->rcuname, __entry->rhp, __entry->func, __entry->qlen) | ||
292 | ); | ||
293 | |||
294 | /* | ||
295 | * Tracepoint for the registration of a single RCU callback of the special | ||
296 | * kfree() form. The first argument is the RCU type, the second argument | ||
297 | * is a pointer to the RCU callback, the third argument is the offset | ||
298 | * of the callback within the enclosing RCU-protected data structure, | ||
299 | * and the fourth argument is the new RCU callback queue length for the | ||
300 | * current CPU. | ||
301 | */ | ||
302 | TRACE_EVENT(rcu_kfree_callback, | ||
303 | |||
304 | TP_PROTO(char *rcuname, struct rcu_head *rhp, unsigned long offset, | ||
305 | long qlen), | ||
306 | |||
307 | TP_ARGS(rcuname, rhp, offset, qlen), | ||
308 | |||
309 | TP_STRUCT__entry( | ||
310 | __field(char *, rcuname) | ||
311 | __field(void *, rhp) | ||
312 | __field(unsigned long, offset) | ||
313 | __field(long, qlen) | ||
314 | ), | ||
315 | |||
316 | TP_fast_assign( | ||
317 | __entry->rcuname = rcuname; | ||
318 | __entry->rhp = rhp; | ||
319 | __entry->offset = offset; | ||
320 | __entry->qlen = qlen; | ||
321 | ), | ||
322 | |||
323 | TP_printk("%s rhp=%p func=%ld %ld", | ||
324 | __entry->rcuname, __entry->rhp, __entry->offset, | ||
325 | __entry->qlen) | ||
326 | ); | ||
327 | |||
37 | /* | 328 | /* |
38 | * Tracepoint for marking the beginning rcu_do_batch, performed to start | 329 | * Tracepoint for marking the beginning rcu_do_batch, performed to start |
39 | * RCU callback invocation. The first argument is the RCU flavor, | 330 | * RCU callback invocation. The first argument is the RCU flavor, |
@@ -65,50 +356,58 @@ TRACE_EVENT(rcu_batch_start, | |||
65 | 356 | ||
66 | /* | 357 | /* |
67 | * Tracepoint for the invocation of a single RCU callback function. | 358 | * Tracepoint for the invocation of a single RCU callback function. |
68 | * The argument is a pointer to the RCU callback itself. | 359 | * The first argument is the type of RCU, and the second argument is |
360 | * a pointer to the RCU callback itself. | ||
69 | */ | 361 | */ |
70 | TRACE_EVENT(rcu_invoke_callback, | 362 | TRACE_EVENT(rcu_invoke_callback, |
71 | 363 | ||
72 | TP_PROTO(struct rcu_head *rhp), | 364 | TP_PROTO(char *rcuname, struct rcu_head *rhp), |
73 | 365 | ||
74 | TP_ARGS(rhp), | 366 | TP_ARGS(rcuname, rhp), |
75 | 367 | ||
76 | TP_STRUCT__entry( | 368 | TP_STRUCT__entry( |
77 | __field(void *, rhp) | 369 | __field(char *, rcuname) |
78 | __field(void *, func) | 370 | __field(void *, rhp) |
371 | __field(void *, func) | ||
79 | ), | 372 | ), |
80 | 373 | ||
81 | TP_fast_assign( | 374 | TP_fast_assign( |
375 | __entry->rcuname = rcuname; | ||
82 | __entry->rhp = rhp; | 376 | __entry->rhp = rhp; |
83 | __entry->func = rhp->func; | 377 | __entry->func = rhp->func; |
84 | ), | 378 | ), |
85 | 379 | ||
86 | TP_printk("rhp=%p func=%pf", __entry->rhp, __entry->func) | 380 | TP_printk("%s rhp=%p func=%pf", |
381 | __entry->rcuname, __entry->rhp, __entry->func) | ||
87 | ); | 382 | ); |
88 | 383 | ||
89 | /* | 384 | /* |
90 | * Tracepoint for the invocation of a single RCU callback of the special | 385 | * Tracepoint for the invocation of a single RCU callback of the special |
91 | * kfree() form. The first argument is a pointer to the RCU callback | 386 | * kfree() form. The first argument is the RCU flavor, the second |
92 | * and the second argument is the offset of the callback within the | 387 | * argument is a pointer to the RCU callback, and the third argument |
93 | * enclosing RCU-protected data structure. | 388 | * is the offset of the callback within the enclosing RCU-protected |
389 | * data structure. | ||
94 | */ | 390 | */ |
95 | TRACE_EVENT(rcu_invoke_kfree_callback, | 391 | TRACE_EVENT(rcu_invoke_kfree_callback, |
96 | 392 | ||
97 | TP_PROTO(struct rcu_head *rhp, unsigned long offset), | 393 | TP_PROTO(char *rcuname, struct rcu_head *rhp, unsigned long offset), |
98 | 394 | ||
99 | TP_ARGS(rhp, offset), | 395 | TP_ARGS(rcuname, rhp, offset), |
100 | 396 | ||
101 | TP_STRUCT__entry( | 397 | TP_STRUCT__entry( |
102 | __field(void *, rhp) | 398 | __field(char *, rcuname) |
399 | __field(void *, rhp) | ||
103 | __field(unsigned long, offset) | 400 | __field(unsigned long, offset) |
104 | ), | 401 | ), |
105 | 402 | ||
106 | TP_fast_assign( | 403 | TP_fast_assign( |
404 | __entry->rcuname = rcuname; | ||
107 | __entry->rhp = rhp; | 405 | __entry->rhp = rhp; |
108 | __entry->offset = offset; | 406 | __entry->offset = offset; |
109 | ), | 407 | ), |
110 | 408 | ||
111 | TP_printk("rhp=%p func=%ld", __entry->rhp, __entry->offset) | 409 | TP_printk("%s rhp=%p func=%ld", |
410 | __entry->rcuname, __entry->rhp, __entry->offset) | ||
112 | ); | 411 | ); |
113 | 412 | ||
114 | /* | 413 | /* |
@@ -136,6 +435,24 @@ TRACE_EVENT(rcu_batch_end, | |||
136 | __entry->rcuname, __entry->callbacks_invoked) | 435 | __entry->rcuname, __entry->callbacks_invoked) |
137 | ); | 436 | ); |
138 | 437 | ||
438 | #else /* #ifdef CONFIG_RCU_TRACE */ | ||
439 | |||
440 | #define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0) | ||
441 | #define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, qsmask) do { } while (0) | ||
442 | #define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) | ||
443 | #define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) | ||
444 | #define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks) do { } while (0) | ||
445 | #define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0) | ||
446 | #define trace_rcu_dyntick(polarity) do { } while (0) | ||
447 | #define trace_rcu_callback(rcuname, rhp, qlen) do { } while (0) | ||
448 | #define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen) do { } while (0) | ||
449 | #define trace_rcu_batch_start(rcuname, qlen, blimit) do { } while (0) | ||
450 | #define trace_rcu_invoke_callback(rcuname, rhp) do { } while (0) | ||
451 | #define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0) | ||
452 | #define trace_rcu_batch_end(rcuname, callbacks_invoked) do { } while (0) | ||
453 | |||
454 | #endif /* #else #ifdef CONFIG_RCU_TRACE */ | ||
455 | |||
139 | #endif /* _TRACE_RCU_H */ | 456 | #endif /* _TRACE_RCU_H */ |
140 | 457 | ||
141 | /* This part must be outside protection */ | 458 | /* This part must be outside protection */ |
diff --git a/kernel/rcu.h b/kernel/rcu.h index d7f00ec8b47b..f600868d550d 100644 --- a/kernel/rcu.h +++ b/kernel/rcu.h | |||
@@ -69,15 +69,15 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head) | |||
69 | 69 | ||
70 | extern void kfree(const void *); | 70 | extern void kfree(const void *); |
71 | 71 | ||
72 | static inline void __rcu_reclaim(struct rcu_head *head) | 72 | static inline void __rcu_reclaim(char *rn, struct rcu_head *head) |
73 | { | 73 | { |
74 | unsigned long offset = (unsigned long)head->func; | 74 | unsigned long offset = (unsigned long)head->func; |
75 | 75 | ||
76 | if (__is_kfree_rcu_offset(offset)) { | 76 | if (__is_kfree_rcu_offset(offset)) { |
77 | RCU_TRACE(trace_rcu_invoke_kfree_callback(head, offset)); | 77 | RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); |
78 | kfree((void *)head - offset); | 78 | kfree((void *)head - offset); |
79 | } else { | 79 | } else { |
80 | RCU_TRACE(trace_rcu_invoke_callback(head)); | 80 | RCU_TRACE(trace_rcu_invoke_callback(rn, head)); |
81 | head->func(head); | 81 | head->func(head); |
82 | } | 82 | } |
83 | } | 83 | } |
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index c9321d86999b..da775c87f27f 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c | |||
@@ -147,6 +147,7 @@ void rcu_check_callbacks(int cpu, int user) | |||
147 | */ | 147 | */ |
148 | static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) | 148 | static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) |
149 | { | 149 | { |
150 | char *rn = NULL; | ||
150 | struct rcu_head *next, *list; | 151 | struct rcu_head *next, *list; |
151 | unsigned long flags; | 152 | unsigned long flags; |
152 | RCU_TRACE(int cb_count = 0); | 153 | RCU_TRACE(int cb_count = 0); |
@@ -171,12 +172,13 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) | |||
171 | local_irq_restore(flags); | 172 | local_irq_restore(flags); |
172 | 173 | ||
173 | /* Invoke the callbacks on the local list. */ | 174 | /* Invoke the callbacks on the local list. */ |
175 | RCU_TRACE(rn = rcp->name); | ||
174 | while (list) { | 176 | while (list) { |
175 | next = list->next; | 177 | next = list->next; |
176 | prefetch(next); | 178 | prefetch(next); |
177 | debug_rcu_head_unqueue(list); | 179 | debug_rcu_head_unqueue(list); |
178 | local_bh_disable(); | 180 | local_bh_disable(); |
179 | __rcu_reclaim(list); | 181 | __rcu_reclaim(rn, list); |
180 | local_bh_enable(); | 182 | local_bh_enable(); |
181 | list = next; | 183 | list = next; |
182 | RCU_TRACE(cb_count++); | 184 | RCU_TRACE(cb_count++); |
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 4e24399cabcf..7e0282949f8a 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -166,6 +166,8 @@ void rcu_sched_qs(int cpu) | |||
166 | 166 | ||
167 | rdp->passed_quiesc_completed = rdp->gpnum - 1; | 167 | rdp->passed_quiesc_completed = rdp->gpnum - 1; |
168 | barrier(); | 168 | barrier(); |
169 | if (rdp->passed_quiesc == 0) | ||
170 | trace_rcu_grace_period("rcu_sched", rdp->gpnum, "cpuqs"); | ||
169 | rdp->passed_quiesc = 1; | 171 | rdp->passed_quiesc = 1; |
170 | } | 172 | } |
171 | 173 | ||
@@ -175,6 +177,8 @@ void rcu_bh_qs(int cpu) | |||
175 | 177 | ||
176 | rdp->passed_quiesc_completed = rdp->gpnum - 1; | 178 | rdp->passed_quiesc_completed = rdp->gpnum - 1; |
177 | barrier(); | 179 | barrier(); |
180 | if (rdp->passed_quiesc == 0) | ||
181 | trace_rcu_grace_period("rcu_bh", rdp->gpnum, "cpuqs"); | ||
178 | rdp->passed_quiesc = 1; | 182 | rdp->passed_quiesc = 1; |
179 | } | 183 | } |
180 | 184 | ||
@@ -319,6 +323,7 @@ static int rcu_implicit_offline_qs(struct rcu_data *rdp) | |||
319 | * trust its state not to change because interrupts are disabled. | 323 | * trust its state not to change because interrupts are disabled. |
320 | */ | 324 | */ |
321 | if (cpu_is_offline(rdp->cpu)) { | 325 | if (cpu_is_offline(rdp->cpu)) { |
326 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "ofl"); | ||
322 | rdp->offline_fqs++; | 327 | rdp->offline_fqs++; |
323 | return 1; | 328 | return 1; |
324 | } | 329 | } |
@@ -359,6 +364,7 @@ void rcu_enter_nohz(void) | |||
359 | local_irq_restore(flags); | 364 | local_irq_restore(flags); |
360 | return; | 365 | return; |
361 | } | 366 | } |
367 | trace_rcu_dyntick("Start"); | ||
362 | /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ | 368 | /* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */ |
363 | smp_mb__before_atomic_inc(); /* See above. */ | 369 | smp_mb__before_atomic_inc(); /* See above. */ |
364 | atomic_inc(&rdtp->dynticks); | 370 | atomic_inc(&rdtp->dynticks); |
@@ -396,6 +402,7 @@ void rcu_exit_nohz(void) | |||
396 | /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ | 402 | /* CPUs seeing atomic_inc() must see later RCU read-side crit sects */ |
397 | smp_mb__after_atomic_inc(); /* See above. */ | 403 | smp_mb__after_atomic_inc(); /* See above. */ |
398 | WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); | 404 | WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1)); |
405 | trace_rcu_dyntick("End"); | ||
399 | local_irq_restore(flags); | 406 | local_irq_restore(flags); |
400 | } | 407 | } |
401 | 408 | ||
@@ -501,6 +508,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
501 | * of the current RCU grace period. | 508 | * of the current RCU grace period. |
502 | */ | 509 | */ |
503 | if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) { | 510 | if ((curr & 0x1) == 0 || ULONG_CMP_GE(curr, snap + 2)) { |
511 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "dti"); | ||
504 | rdp->dynticks_fqs++; | 512 | rdp->dynticks_fqs++; |
505 | return 1; | 513 | return 1; |
506 | } | 514 | } |
@@ -683,6 +691,7 @@ static void __note_new_gpnum(struct rcu_state *rsp, struct rcu_node *rnp, struct | |||
683 | * go looking for one. | 691 | * go looking for one. |
684 | */ | 692 | */ |
685 | rdp->gpnum = rnp->gpnum; | 693 | rdp->gpnum = rnp->gpnum; |
694 | trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpustart"); | ||
686 | if (rnp->qsmask & rdp->grpmask) { | 695 | if (rnp->qsmask & rdp->grpmask) { |
687 | rdp->qs_pending = 1; | 696 | rdp->qs_pending = 1; |
688 | rdp->passed_quiesc = 0; | 697 | rdp->passed_quiesc = 0; |
@@ -746,6 +755,7 @@ __rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_dat | |||
746 | 755 | ||
747 | /* Remember that we saw this grace-period completion. */ | 756 | /* Remember that we saw this grace-period completion. */ |
748 | rdp->completed = rnp->completed; | 757 | rdp->completed = rnp->completed; |
758 | trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpuend"); | ||
749 | 759 | ||
750 | /* | 760 | /* |
751 | * If we were in an extended quiescent state, we may have | 761 | * If we were in an extended quiescent state, we may have |
@@ -856,6 +866,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) | |||
856 | 866 | ||
857 | /* Advance to a new grace period and initialize state. */ | 867 | /* Advance to a new grace period and initialize state. */ |
858 | rsp->gpnum++; | 868 | rsp->gpnum++; |
869 | trace_rcu_grace_period(rsp->name, rsp->gpnum, "start"); | ||
859 | WARN_ON_ONCE(rsp->signaled == RCU_GP_INIT); | 870 | WARN_ON_ONCE(rsp->signaled == RCU_GP_INIT); |
860 | rsp->signaled = RCU_GP_INIT; /* Hold off force_quiescent_state. */ | 871 | rsp->signaled = RCU_GP_INIT; /* Hold off force_quiescent_state. */ |
861 | rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; | 872 | rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; |
@@ -870,6 +881,9 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) | |||
870 | rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state OK. */ | 881 | rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state OK. */ |
871 | rcu_start_gp_per_cpu(rsp, rnp, rdp); | 882 | rcu_start_gp_per_cpu(rsp, rnp, rdp); |
872 | rcu_preempt_boost_start_gp(rnp); | 883 | rcu_preempt_boost_start_gp(rnp); |
884 | trace_rcu_grace_period_init(rsp->name, rnp->gpnum, | ||
885 | rnp->level, rnp->grplo, | ||
886 | rnp->grphi, rnp->qsmask); | ||
873 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 887 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
874 | return; | 888 | return; |
875 | } | 889 | } |
@@ -906,6 +920,9 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) | |||
906 | if (rnp == rdp->mynode) | 920 | if (rnp == rdp->mynode) |
907 | rcu_start_gp_per_cpu(rsp, rnp, rdp); | 921 | rcu_start_gp_per_cpu(rsp, rnp, rdp); |
908 | rcu_preempt_boost_start_gp(rnp); | 922 | rcu_preempt_boost_start_gp(rnp); |
923 | trace_rcu_grace_period_init(rsp->name, rnp->gpnum, | ||
924 | rnp->level, rnp->grplo, | ||
925 | rnp->grphi, rnp->qsmask); | ||
909 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ | 926 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ |
910 | } | 927 | } |
911 | 928 | ||
@@ -939,6 +956,7 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) | |||
939 | if (gp_duration > rsp->gp_max) | 956 | if (gp_duration > rsp->gp_max) |
940 | rsp->gp_max = gp_duration; | 957 | rsp->gp_max = gp_duration; |
941 | rsp->completed = rsp->gpnum; | 958 | rsp->completed = rsp->gpnum; |
959 | trace_rcu_grace_period(rsp->name, rsp->completed, "end"); | ||
942 | rsp->signaled = RCU_GP_IDLE; | 960 | rsp->signaled = RCU_GP_IDLE; |
943 | rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ | 961 | rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ |
944 | } | 962 | } |
@@ -967,6 +985,10 @@ rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp, | |||
967 | return; | 985 | return; |
968 | } | 986 | } |
969 | rnp->qsmask &= ~mask; | 987 | rnp->qsmask &= ~mask; |
988 | trace_rcu_quiescent_state_report(rsp->name, rnp->gpnum, | ||
989 | mask, rnp->qsmask, rnp->level, | ||
990 | rnp->grplo, rnp->grphi, | ||
991 | !!rnp->gp_tasks); | ||
970 | if (rnp->qsmask != 0 || rcu_preempt_blocked_readers_cgp(rnp)) { | 992 | if (rnp->qsmask != 0 || rcu_preempt_blocked_readers_cgp(rnp)) { |
971 | 993 | ||
972 | /* Other bits still set at this level, so done. */ | 994 | /* Other bits still set at this level, so done. */ |
@@ -1135,11 +1157,20 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) | |||
1135 | if (rnp->qsmaskinit != 0) { | 1157 | if (rnp->qsmaskinit != 0) { |
1136 | if (rnp != rdp->mynode) | 1158 | if (rnp != rdp->mynode) |
1137 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ | 1159 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ |
1160 | else | ||
1161 | trace_rcu_grace_period(rsp->name, | ||
1162 | rnp->gpnum + 1 - | ||
1163 | !!(rnp->qsmask & mask), | ||
1164 | "cpuofl"); | ||
1138 | break; | 1165 | break; |
1139 | } | 1166 | } |
1140 | if (rnp == rdp->mynode) | 1167 | if (rnp == rdp->mynode) { |
1168 | trace_rcu_grace_period(rsp->name, | ||
1169 | rnp->gpnum + 1 - | ||
1170 | !!(rnp->qsmask & mask), | ||
1171 | "cpuofl"); | ||
1141 | need_report = rcu_preempt_offline_tasks(rsp, rnp, rdp); | 1172 | need_report = rcu_preempt_offline_tasks(rsp, rnp, rdp); |
1142 | else | 1173 | } else |
1143 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ | 1174 | raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ |
1144 | mask = rnp->grpmask; | 1175 | mask = rnp->grpmask; |
1145 | rnp = rnp->parent; | 1176 | rnp = rnp->parent; |
@@ -1226,7 +1257,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1226 | next = list->next; | 1257 | next = list->next; |
1227 | prefetch(next); | 1258 | prefetch(next); |
1228 | debug_rcu_head_unqueue(list); | 1259 | debug_rcu_head_unqueue(list); |
1229 | __rcu_reclaim(list); | 1260 | __rcu_reclaim(rsp->name, list); |
1230 | list = next; | 1261 | list = next; |
1231 | if (++count >= bl) | 1262 | if (++count >= bl) |
1232 | break; | 1263 | break; |
@@ -1552,6 +1583,12 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1552 | rdp->nxttail[RCU_NEXT_TAIL] = &head->next; | 1583 | rdp->nxttail[RCU_NEXT_TAIL] = &head->next; |
1553 | rdp->qlen++; | 1584 | rdp->qlen++; |
1554 | 1585 | ||
1586 | if (__is_kfree_rcu_offset((unsigned long)func)) | ||
1587 | trace_rcu_kfree_callback(rsp->name, head, (unsigned long)func, | ||
1588 | rdp->qlen); | ||
1589 | else | ||
1590 | trace_rcu_callback(rsp->name, head, rdp->qlen); | ||
1591 | |||
1555 | /* If interrupts were disabled, don't dive into RCU core. */ | 1592 | /* If interrupts were disabled, don't dive into RCU core. */ |
1556 | if (irqs_disabled_flags(flags)) { | 1593 | if (irqs_disabled_flags(flags)) { |
1557 | local_irq_restore(flags); | 1594 | local_irq_restore(flags); |
@@ -1850,6 +1887,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) | |||
1850 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); | 1887 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); |
1851 | #endif /* #ifdef CONFIG_NO_HZ */ | 1888 | #endif /* #ifdef CONFIG_NO_HZ */ |
1852 | rdp->cpu = cpu; | 1889 | rdp->cpu = cpu; |
1890 | rdp->rsp = rsp; | ||
1853 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 1891 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
1854 | } | 1892 | } |
1855 | 1893 | ||
@@ -1898,6 +1936,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) | |||
1898 | rdp->gpnum = rnp->completed; /* if GP in progress... */ | 1936 | rdp->gpnum = rnp->completed; /* if GP in progress... */ |
1899 | rdp->completed = rnp->completed; | 1937 | rdp->completed = rnp->completed; |
1900 | rdp->passed_quiesc_completed = rnp->completed - 1; | 1938 | rdp->passed_quiesc_completed = rnp->completed - 1; |
1939 | trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpuonl"); | ||
1901 | } | 1940 | } |
1902 | raw_spin_unlock(&rnp->lock); /* irqs already disabled. */ | 1941 | raw_spin_unlock(&rnp->lock); /* irqs already disabled. */ |
1903 | rnp = rnp->parent; | 1942 | rnp = rnp->parent; |
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index eee6c9406b46..d11a0065321c 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -299,6 +299,7 @@ struct rcu_data { | |||
299 | unsigned long n_rp_need_nothing; | 299 | unsigned long n_rp_need_nothing; |
300 | 300 | ||
301 | int cpu; | 301 | int cpu; |
302 | struct rcu_state *rsp; | ||
302 | }; | 303 | }; |
303 | 304 | ||
304 | /* Values for signaled field in struct rcu_state. */ | 305 | /* Values for signaled field in struct rcu_state. */ |
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 94d9ca1e4061..bdb2e82f78d3 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
@@ -124,6 +124,8 @@ static void rcu_preempt_qs(int cpu) | |||
124 | 124 | ||
125 | rdp->passed_quiesc_completed = rdp->gpnum - 1; | 125 | rdp->passed_quiesc_completed = rdp->gpnum - 1; |
126 | barrier(); | 126 | barrier(); |
127 | if (rdp->passed_quiesc == 0) | ||
128 | trace_rcu_grace_period("rcu_preempt", rdp->gpnum, "cpuqs"); | ||
127 | rdp->passed_quiesc = 1; | 129 | rdp->passed_quiesc = 1; |
128 | current->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS; | 130 | current->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS; |
129 | } | 131 | } |
@@ -190,6 +192,11 @@ static void rcu_preempt_note_context_switch(int cpu) | |||
190 | if (rnp->qsmask & rdp->grpmask) | 192 | if (rnp->qsmask & rdp->grpmask) |
191 | rnp->gp_tasks = &t->rcu_node_entry; | 193 | rnp->gp_tasks = &t->rcu_node_entry; |
192 | } | 194 | } |
195 | trace_rcu_preempt_task(rdp->rsp->name, | ||
196 | t->pid, | ||
197 | (rnp->qsmask & rdp->grpmask) | ||
198 | ? rnp->gpnum | ||
199 | : rnp->gpnum + 1); | ||
193 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 200 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
194 | } else if (t->rcu_read_lock_nesting < 0 && | 201 | } else if (t->rcu_read_lock_nesting < 0 && |
195 | t->rcu_read_unlock_special) { | 202 | t->rcu_read_unlock_special) { |
@@ -344,6 +351,8 @@ static noinline void rcu_read_unlock_special(struct task_struct *t) | |||
344 | smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ | 351 | smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ |
345 | np = rcu_next_node_entry(t, rnp); | 352 | np = rcu_next_node_entry(t, rnp); |
346 | list_del_init(&t->rcu_node_entry); | 353 | list_del_init(&t->rcu_node_entry); |
354 | trace_rcu_unlock_preempted_task("rcu_preempt", | ||
355 | rnp->gpnum, t->pid); | ||
347 | if (&t->rcu_node_entry == rnp->gp_tasks) | 356 | if (&t->rcu_node_entry == rnp->gp_tasks) |
348 | rnp->gp_tasks = np; | 357 | rnp->gp_tasks = np; |
349 | if (&t->rcu_node_entry == rnp->exp_tasks) | 358 | if (&t->rcu_node_entry == rnp->exp_tasks) |
@@ -364,10 +373,17 @@ static noinline void rcu_read_unlock_special(struct task_struct *t) | |||
364 | * we aren't waiting on any CPUs, report the quiescent state. | 373 | * we aren't waiting on any CPUs, report the quiescent state. |
365 | * Note that rcu_report_unblock_qs_rnp() releases rnp->lock. | 374 | * Note that rcu_report_unblock_qs_rnp() releases rnp->lock. |
366 | */ | 375 | */ |
367 | if (empty) | 376 | if (!empty && !rcu_preempt_blocked_readers_cgp(rnp)) { |
368 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 377 | trace_rcu_quiescent_state_report("preempt_rcu", |
369 | else | 378 | rnp->gpnum, |
379 | 0, rnp->qsmask, | ||
380 | rnp->level, | ||
381 | rnp->grplo, | ||
382 | rnp->grphi, | ||
383 | !!rnp->gp_tasks); | ||
370 | rcu_report_unblock_qs_rnp(rnp, flags); | 384 | rcu_report_unblock_qs_rnp(rnp, flags); |
385 | } else | ||
386 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | ||
371 | 387 | ||
372 | #ifdef CONFIG_RCU_BOOST | 388 | #ifdef CONFIG_RCU_BOOST |
373 | /* Unboost if we were boosted. */ | 389 | /* Unboost if we were boosted. */ |