diff options
-rw-r--r-- | Documentation/trace/ftrace.txt | 6 | ||||
-rw-r--r-- | kernel/trace/trace_functions.c | 44 |
2 files changed, 50 insertions, 0 deletions
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index cc9ec57e157c..b937c6e2163c 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt | |||
@@ -2437,6 +2437,12 @@ The following commands are supported: | |||
2437 | is hit. Perhaps its a function that is called before a tripple | 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. | 2438 | fault happens and does not allow you to get a regular dump. |
2439 | 2439 | ||
2440 | - cpudump | ||
2441 | When the function is hit, it will dump the contents of the ftrace | ||
2442 | ring buffer for the current CPU to the console. Unlike the "dump" | ||
2443 | command, it only prints out the contents of the ring buffer for the | ||
2444 | CPU that executed the function that triggered the dump. | ||
2445 | |||
2440 | trace_pipe | 2446 | trace_pipe |
2441 | ---------- | 2447 | ---------- |
2442 | 2448 | ||
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index d7c8719734b8..b863f93b30f3 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c | |||
@@ -297,6 +297,14 @@ ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, void **data) | |||
297 | ftrace_dump(DUMP_ALL); | 297 | ftrace_dump(DUMP_ALL); |
298 | } | 298 | } |
299 | 299 | ||
300 | /* Only dump the current CPU buffer. */ | ||
301 | static void | ||
302 | ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, void **data) | ||
303 | { | ||
304 | if (update_count(data)) | ||
305 | ftrace_dump(DUMP_ORIG); | ||
306 | } | ||
307 | |||
300 | static int | 308 | static int |
301 | ftrace_probe_print(const char *name, struct seq_file *m, | 309 | ftrace_probe_print(const char *name, struct seq_file *m, |
302 | unsigned long ip, void *data) | 310 | unsigned long ip, void *data) |
@@ -341,6 +349,13 @@ ftrace_dump_print(struct seq_file *m, unsigned long ip, | |||
341 | return ftrace_probe_print("dump", m, ip, data); | 349 | return ftrace_probe_print("dump", m, ip, data); |
342 | } | 350 | } |
343 | 351 | ||
352 | static int | ||
353 | ftrace_cpudump_print(struct seq_file *m, unsigned long ip, | ||
354 | struct ftrace_probe_ops *ops, void *data) | ||
355 | { | ||
356 | return ftrace_probe_print("cpudump", m, ip, data); | ||
357 | } | ||
358 | |||
344 | static struct ftrace_probe_ops traceon_count_probe_ops = { | 359 | static struct ftrace_probe_ops traceon_count_probe_ops = { |
345 | .func = ftrace_traceon_count, | 360 | .func = ftrace_traceon_count, |
346 | .print = ftrace_traceon_print, | 361 | .print = ftrace_traceon_print, |
@@ -361,6 +376,11 @@ static struct ftrace_probe_ops dump_probe_ops = { | |||
361 | .print = ftrace_dump_print, | 376 | .print = ftrace_dump_print, |
362 | }; | 377 | }; |
363 | 378 | ||
379 | static struct ftrace_probe_ops cpudump_probe_ops = { | ||
380 | .func = ftrace_cpudump_probe, | ||
381 | .print = ftrace_cpudump_print, | ||
382 | }; | ||
383 | |||
364 | static struct ftrace_probe_ops traceon_probe_ops = { | 384 | static struct ftrace_probe_ops traceon_probe_ops = { |
365 | .func = ftrace_traceon, | 385 | .func = ftrace_traceon, |
366 | .print = ftrace_traceon_print, | 386 | .print = ftrace_traceon_print, |
@@ -457,6 +477,19 @@ ftrace_dump_callback(struct ftrace_hash *hash, | |||
457 | "1", enable); | 477 | "1", enable); |
458 | } | 478 | } |
459 | 479 | ||
480 | static int | ||
481 | ftrace_cpudump_callback(struct ftrace_hash *hash, | ||
482 | char *glob, char *cmd, char *param, int enable) | ||
483 | { | ||
484 | struct ftrace_probe_ops *ops; | ||
485 | |||
486 | ops = &cpudump_probe_ops; | ||
487 | |||
488 | /* Only dump once. */ | ||
489 | return ftrace_trace_probe_callback(ops, hash, glob, cmd, | ||
490 | "1", enable); | ||
491 | } | ||
492 | |||
460 | static struct ftrace_func_command ftrace_traceon_cmd = { | 493 | static struct ftrace_func_command ftrace_traceon_cmd = { |
461 | .name = "traceon", | 494 | .name = "traceon", |
462 | .func = ftrace_trace_onoff_callback, | 495 | .func = ftrace_trace_onoff_callback, |
@@ -477,6 +510,11 @@ static struct ftrace_func_command ftrace_dump_cmd = { | |||
477 | .func = ftrace_dump_callback, | 510 | .func = ftrace_dump_callback, |
478 | }; | 511 | }; |
479 | 512 | ||
513 | static struct ftrace_func_command ftrace_cpudump_cmd = { | ||
514 | .name = "cpudump", | ||
515 | .func = ftrace_cpudump_callback, | ||
516 | }; | ||
517 | |||
480 | static int __init init_func_cmd_traceon(void) | 518 | static int __init init_func_cmd_traceon(void) |
481 | { | 519 | { |
482 | int ret; | 520 | int ret; |
@@ -497,8 +535,14 @@ static int __init init_func_cmd_traceon(void) | |||
497 | if (ret) | 535 | if (ret) |
498 | goto out_free_stacktrace; | 536 | goto out_free_stacktrace; |
499 | 537 | ||
538 | ret = register_ftrace_command(&ftrace_cpudump_cmd); | ||
539 | if (ret) | ||
540 | goto out_free_dump; | ||
541 | |||
500 | return 0; | 542 | return 0; |
501 | 543 | ||
544 | out_free_dump: | ||
545 | unregister_ftrace_command(&ftrace_dump_cmd); | ||
502 | out_free_stacktrace: | 546 | out_free_stacktrace: |
503 | unregister_ftrace_command(&ftrace_stacktrace_cmd); | 547 | unregister_ftrace_command(&ftrace_stacktrace_cmd); |
504 | out_free_traceon: | 548 | out_free_traceon: |