diff options
Diffstat (limited to 'kernel/trace/trace_selftest.c')
-rw-r--r-- | kernel/trace/trace_selftest.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 38856ba78a92..b56dcf7d3566 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
@@ -248,6 +248,28 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) | |||
248 | 248 | ||
249 | 249 | ||
250 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 250 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
251 | |||
252 | /* Maximum number of functions to trace before diagnosing a hang */ | ||
253 | #define GRAPH_MAX_FUNC_TEST 100000000 | ||
254 | |||
255 | static void __ftrace_dump(bool disable_tracing); | ||
256 | static unsigned int graph_hang_thresh; | ||
257 | |||
258 | /* Wrap the real function entry probe to avoid possible hanging */ | ||
259 | static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace) | ||
260 | { | ||
261 | /* This is harmlessly racy, we want to approximately detect a hang */ | ||
262 | if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) { | ||
263 | ftrace_graph_stop(); | ||
264 | printk(KERN_WARNING "BUG: Function graph tracer hang!\n"); | ||
265 | if (ftrace_dump_on_oops) | ||
266 | __ftrace_dump(false); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | return trace_graph_entry(trace); | ||
271 | } | ||
272 | |||
251 | /* | 273 | /* |
252 | * Pretty much the same than for the function tracer from which the selftest | 274 | * Pretty much the same than for the function tracer from which the selftest |
253 | * has been borrowed. | 275 | * has been borrowed. |
@@ -259,15 +281,29 @@ trace_selftest_startup_function_graph(struct tracer *trace, | |||
259 | int ret; | 281 | int ret; |
260 | unsigned long count; | 282 | unsigned long count; |
261 | 283 | ||
262 | ret = tracer_init(trace, tr); | 284 | /* |
285 | * Simulate the init() callback but we attach a watchdog callback | ||
286 | * to detect and recover from possible hangs | ||
287 | */ | ||
288 | tracing_reset_online_cpus(tr); | ||
289 | ret = register_ftrace_graph(&trace_graph_return, | ||
290 | &trace_graph_entry_watchdog); | ||
263 | if (ret) { | 291 | if (ret) { |
264 | warn_failed_init_tracer(trace, ret); | 292 | warn_failed_init_tracer(trace, ret); |
265 | goto out; | 293 | goto out; |
266 | } | 294 | } |
295 | tracing_start_cmdline_record(); | ||
267 | 296 | ||
268 | /* Sleep for a 1/10 of a second */ | 297 | /* Sleep for a 1/10 of a second */ |
269 | msleep(100); | 298 | msleep(100); |
270 | 299 | ||
300 | /* Have we just recovered from a hang? */ | ||
301 | if (graph_hang_thresh > GRAPH_MAX_FUNC_TEST) { | ||
302 | trace->reset(tr); | ||
303 | ret = -1; | ||
304 | goto out; | ||
305 | } | ||
306 | |||
271 | tracing_stop(); | 307 | tracing_stop(); |
272 | 308 | ||
273 | /* check the trace buffer */ | 309 | /* check the trace buffer */ |