aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/trace/ftrace.txt7
-rw-r--r--kernel/trace/trace_functions.c59
2 files changed, 61 insertions, 5 deletions
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index bfe8c29b1f1d..cc9ec57e157c 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -2430,6 +2430,13 @@ The following commands are supported:
2430 echo '!schedule:disable_event:sched:sched_switch' > \ 2430 echo '!schedule:disable_event:sched:sched_switch' > \
2431 set_ftrace_filter 2431 set_ftrace_filter
2432 2432
2433- dump
2434 When the function is hit, it will dump the contents of the ftrace
2435 ring buffer to the console. This is useful if you need to debug
2436 something, and want to dump the trace when a certain function
2437 is hit. Perhaps its a function that is called before a tripple
2438 fault happens and does not allow you to get a regular dump.
2439
2433trace_pipe 2440trace_pipe
2434---------- 2441----------
2435 2442
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index c4d6d7191988..d7c8719734b8 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -290,6 +290,13 @@ ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
290 trace_dump_stack(STACK_SKIP); 290 trace_dump_stack(STACK_SKIP);
291} 291}
292 292
293static void
294ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, void **data)
295{
296 if (update_count(data))
297 ftrace_dump(DUMP_ALL);
298}
299
293static int 300static int
294ftrace_probe_print(const char *name, struct seq_file *m, 301ftrace_probe_print(const char *name, struct seq_file *m,
295 unsigned long ip, void *data) 302 unsigned long ip, void *data)
@@ -327,6 +334,13 @@ ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
327 return ftrace_probe_print("stacktrace", m, ip, data); 334 return ftrace_probe_print("stacktrace", m, ip, data);
328} 335}
329 336
337static int
338ftrace_dump_print(struct seq_file *m, unsigned long ip,
339 struct ftrace_probe_ops *ops, void *data)
340{
341 return ftrace_probe_print("dump", m, ip, data);
342}
343
330static struct ftrace_probe_ops traceon_count_probe_ops = { 344static struct ftrace_probe_ops traceon_count_probe_ops = {
331 .func = ftrace_traceon_count, 345 .func = ftrace_traceon_count,
332 .print = ftrace_traceon_print, 346 .print = ftrace_traceon_print,
@@ -342,6 +356,11 @@ static struct ftrace_probe_ops stacktrace_count_probe_ops = {
342 .print = ftrace_stacktrace_print, 356 .print = ftrace_stacktrace_print,
343}; 357};
344 358
359static struct ftrace_probe_ops dump_probe_ops = {
360 .func = ftrace_dump_probe,
361 .print = ftrace_dump_print,
362};
363
345static struct ftrace_probe_ops traceon_probe_ops = { 364static struct ftrace_probe_ops traceon_probe_ops = {
346 .func = ftrace_traceon, 365 .func = ftrace_traceon,
347 .print = ftrace_traceon_print, 366 .print = ftrace_traceon_print,
@@ -425,6 +444,19 @@ ftrace_stacktrace_callback(struct ftrace_hash *hash,
425 param, enable); 444 param, enable);
426} 445}
427 446
447static int
448ftrace_dump_callback(struct ftrace_hash *hash,
449 char *glob, char *cmd, char *param, int enable)
450{
451 struct ftrace_probe_ops *ops;
452
453 ops = &dump_probe_ops;
454
455 /* Only dump once. */
456 return ftrace_trace_probe_callback(ops, hash, glob, cmd,
457 "1", enable);
458}
459
428static struct ftrace_func_command ftrace_traceon_cmd = { 460static struct ftrace_func_command ftrace_traceon_cmd = {
429 .name = "traceon", 461 .name = "traceon",
430 .func = ftrace_trace_onoff_callback, 462 .func = ftrace_trace_onoff_callback,
@@ -440,6 +472,11 @@ static struct ftrace_func_command ftrace_stacktrace_cmd = {
440 .func = ftrace_stacktrace_callback, 472 .func = ftrace_stacktrace_callback,
441}; 473};
442 474
475static struct ftrace_func_command ftrace_dump_cmd = {
476 .name = "dump",
477 .func = ftrace_dump_callback,
478};
479
443static int __init init_func_cmd_traceon(void) 480static int __init init_func_cmd_traceon(void)
444{ 481{
445 int ret; 482 int ret;
@@ -450,13 +487,25 @@ static int __init init_func_cmd_traceon(void)
450 487
451 ret = register_ftrace_command(&ftrace_traceon_cmd); 488 ret = register_ftrace_command(&ftrace_traceon_cmd);
452 if (ret) 489 if (ret)
453 unregister_ftrace_command(&ftrace_traceoff_cmd); 490 goto out_free_traceoff;
454 491
455 ret = register_ftrace_command(&ftrace_stacktrace_cmd); 492 ret = register_ftrace_command(&ftrace_stacktrace_cmd);
456 if (ret) { 493 if (ret)
457 unregister_ftrace_command(&ftrace_traceoff_cmd); 494 goto out_free_traceon;
458 unregister_ftrace_command(&ftrace_traceon_cmd); 495
459 } 496 ret = register_ftrace_command(&ftrace_dump_cmd);
497 if (ret)
498 goto out_free_stacktrace;
499
500 return 0;
501
502 out_free_stacktrace:
503 unregister_ftrace_command(&ftrace_stacktrace_cmd);
504 out_free_traceon:
505 unregister_ftrace_command(&ftrace_traceon_cmd);
506 out_free_traceoff:
507 unregister_ftrace_command(&ftrace_traceoff_cmd);
508
460 return ret; 509 return ret;
461} 510}
462#else 511#else