diff options
| author | Tom Zanussi <tom.zanussi@linux.intel.com> | 2013-10-24 09:59:26 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2013-12-21 22:01:22 -0500 |
| commit | 93e31ffbf417a84fbae518fb46b3ea3f0d8fa6e1 (patch) | |
| tree | c7eb0f81daec69a2505688bb5fcee94e2374be5f /kernel/trace | |
| parent | 2a2df321158817811c5dc206dce808e0aa9f6d89 (diff) | |
tracing: Add 'snapshot' event trigger command
Add 'snapshot' event_command. snapshot event triggers are added by
the user via this command in a similar way and using practically the
same syntax as the analogous 'snapshot' ftrace function command, but
instead of writing to the set_ftrace_filter file, the snapshot event
trigger is written to the per-event 'trigger' files:
echo 'snapshot' > .../somesys/someevent/trigger
The above command will turn on snapshots for someevent i.e. whenever
someevent is hit, a snapshot will be done.
This also adds a 'count' version that limits the number of times the
command will be invoked:
echo 'snapshot:N' > .../somesys/someevent/trigger
Where N is the number of times the command will be invoked.
The above command will snapshot N times for someevent i.e. whenever
someevent is hit N times, a snapshot will be done.
Also adds a new tracing_alloc_snapshot() function - the existing
tracing_snapshot_alloc() function is a special version of
tracing_snapshot() that also does the snapshot allocation - the
snapshot triggers would like to be able to do just the allocation but
not take a snapshot; the existing tracing_snapshot_alloc() in turn now
also calls tracing_alloc_snapshot() underneath to do that allocation.
Link: http://lkml.kernel.org/r/c9524dd07ce01f9dcbd59011290e0a8d5b47d7ad.1382622043.git.tom.zanussi@linux.intel.com
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
[ fix up from kbuild test robot <fengguang.wu@intel.com report ]
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/trace.c | 33 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_events_trigger.c | 85 |
3 files changed, 116 insertions, 3 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 9d20cd9743ef..59bf5b56ccc0 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -595,6 +595,28 @@ void free_snapshot(struct trace_array *tr) | |||
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | /** | 597 | /** |
| 598 | * tracing_alloc_snapshot - allocate snapshot buffer. | ||
| 599 | * | ||
| 600 | * This only allocates the snapshot buffer if it isn't already | ||
| 601 | * allocated - it doesn't also take a snapshot. | ||
| 602 | * | ||
| 603 | * This is meant to be used in cases where the snapshot buffer needs | ||
| 604 | * to be set up for events that can't sleep but need to be able to | ||
| 605 | * trigger a snapshot. | ||
| 606 | */ | ||
| 607 | int tracing_alloc_snapshot(void) | ||
| 608 | { | ||
| 609 | struct trace_array *tr = &global_trace; | ||
| 610 | int ret; | ||
| 611 | |||
| 612 | ret = alloc_snapshot(tr); | ||
| 613 | WARN_ON(ret < 0); | ||
| 614 | |||
| 615 | return ret; | ||
| 616 | } | ||
| 617 | EXPORT_SYMBOL_GPL(tracing_alloc_snapshot); | ||
| 618 | |||
| 619 | /** | ||
| 598 | * trace_snapshot_alloc - allocate and take a snapshot of the current buffer. | 620 | * trace_snapshot_alloc - allocate and take a snapshot of the current buffer. |
| 599 | * | 621 | * |
| 600 | * This is similar to trace_snapshot(), but it will allocate the | 622 | * This is similar to trace_snapshot(), but it will allocate the |
| @@ -607,11 +629,10 @@ void free_snapshot(struct trace_array *tr) | |||
| 607 | */ | 629 | */ |
| 608 | void tracing_snapshot_alloc(void) | 630 | void tracing_snapshot_alloc(void) |
| 609 | { | 631 | { |
| 610 | struct trace_array *tr = &global_trace; | ||
| 611 | int ret; | 632 | int ret; |
| 612 | 633 | ||
| 613 | ret = alloc_snapshot(tr); | 634 | ret = tracing_alloc_snapshot(); |
| 614 | if (WARN_ON(ret < 0)) | 635 | if (ret < 0) |
| 615 | return; | 636 | return; |
| 616 | 637 | ||
| 617 | tracing_snapshot(); | 638 | tracing_snapshot(); |
| @@ -623,6 +644,12 @@ void tracing_snapshot(void) | |||
| 623 | WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used"); | 644 | WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used"); |
| 624 | } | 645 | } |
| 625 | EXPORT_SYMBOL_GPL(tracing_snapshot); | 646 | EXPORT_SYMBOL_GPL(tracing_snapshot); |
| 647 | int tracing_alloc_snapshot(void) | ||
| 648 | { | ||
| 649 | WARN_ONCE(1, "Snapshot feature not enabled, but snapshot allocation used"); | ||
| 650 | return -ENODEV; | ||
| 651 | } | ||
| 652 | EXPORT_SYMBOL_GPL(tracing_alloc_snapshot); | ||
| 626 | void tracing_snapshot_alloc(void) | 653 | void tracing_snapshot_alloc(void) |
| 627 | { | 654 | { |
| 628 | /* Give warning */ | 655 | /* Give warning */ |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 9775e518fe77..50723e5e2b3c 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -1211,6 +1211,7 @@ struct event_command { | |||
| 1211 | 1211 | ||
| 1212 | extern int trace_event_enable_disable(struct ftrace_event_file *file, | 1212 | extern int trace_event_enable_disable(struct ftrace_event_file *file, |
| 1213 | int enable, int soft_disable); | 1213 | int enable, int soft_disable); |
| 1214 | extern int tracing_alloc_snapshot(void); | ||
| 1214 | 1215 | ||
| 1215 | extern const char *__start___trace_bprintk_fmt[]; | 1216 | extern const char *__start___trace_bprintk_fmt[]; |
| 1216 | extern const char *__stop___trace_bprintk_fmt[]; | 1217 | extern const char *__stop___trace_bprintk_fmt[]; |
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index 4ea72ee169a7..d775c3da180f 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c | |||
| @@ -696,6 +696,90 @@ static struct event_command trigger_traceoff_cmd = { | |||
| 696 | .get_trigger_ops = onoff_get_trigger_ops, | 696 | .get_trigger_ops = onoff_get_trigger_ops, |
| 697 | }; | 697 | }; |
| 698 | 698 | ||
| 699 | #ifdef CONFIG_TRACER_SNAPSHOT | ||
| 700 | static void | ||
| 701 | snapshot_trigger(struct event_trigger_data *data) | ||
| 702 | { | ||
| 703 | tracing_snapshot(); | ||
| 704 | } | ||
| 705 | |||
| 706 | static void | ||
| 707 | snapshot_count_trigger(struct event_trigger_data *data) | ||
| 708 | { | ||
| 709 | if (!data->count) | ||
| 710 | return; | ||
| 711 | |||
| 712 | if (data->count != -1) | ||
| 713 | (data->count)--; | ||
| 714 | |||
| 715 | snapshot_trigger(data); | ||
| 716 | } | ||
| 717 | |||
| 718 | static int | ||
| 719 | register_snapshot_trigger(char *glob, struct event_trigger_ops *ops, | ||
| 720 | struct event_trigger_data *data, | ||
| 721 | struct ftrace_event_file *file) | ||
| 722 | { | ||
| 723 | int ret = register_trigger(glob, ops, data, file); | ||
| 724 | |||
| 725 | if (ret > 0 && tracing_alloc_snapshot() != 0) { | ||
| 726 | unregister_trigger(glob, ops, data, file); | ||
| 727 | ret = 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | return ret; | ||
| 731 | } | ||
| 732 | |||
| 733 | static int | ||
| 734 | snapshot_trigger_print(struct seq_file *m, struct event_trigger_ops *ops, | ||
| 735 | struct event_trigger_data *data) | ||
| 736 | { | ||
| 737 | return event_trigger_print("snapshot", m, (void *)data->count, | ||
| 738 | data->filter_str); | ||
| 739 | } | ||
| 740 | |||
| 741 | static struct event_trigger_ops snapshot_trigger_ops = { | ||
| 742 | .func = snapshot_trigger, | ||
| 743 | .print = snapshot_trigger_print, | ||
| 744 | .init = event_trigger_init, | ||
| 745 | .free = event_trigger_free, | ||
| 746 | }; | ||
| 747 | |||
| 748 | static struct event_trigger_ops snapshot_count_trigger_ops = { | ||
| 749 | .func = snapshot_count_trigger, | ||
| 750 | .print = snapshot_trigger_print, | ||
| 751 | .init = event_trigger_init, | ||
| 752 | .free = event_trigger_free, | ||
| 753 | }; | ||
| 754 | |||
| 755 | static struct event_trigger_ops * | ||
| 756 | snapshot_get_trigger_ops(char *cmd, char *param) | ||
| 757 | { | ||
| 758 | return param ? &snapshot_count_trigger_ops : &snapshot_trigger_ops; | ||
| 759 | } | ||
| 760 | |||
| 761 | static struct event_command trigger_snapshot_cmd = { | ||
| 762 | .name = "snapshot", | ||
| 763 | .trigger_type = ETT_SNAPSHOT, | ||
| 764 | .func = event_trigger_callback, | ||
| 765 | .reg = register_snapshot_trigger, | ||
| 766 | .unreg = unregister_trigger, | ||
| 767 | .get_trigger_ops = snapshot_get_trigger_ops, | ||
| 768 | }; | ||
| 769 | |||
| 770 | static __init int register_trigger_snapshot_cmd(void) | ||
| 771 | { | ||
| 772 | int ret; | ||
| 773 | |||
| 774 | ret = register_event_command(&trigger_snapshot_cmd); | ||
| 775 | WARN_ON(ret < 0); | ||
| 776 | |||
| 777 | return ret; | ||
| 778 | } | ||
| 779 | #else | ||
| 780 | static __init int register_trigger_snapshot_cmd(void) { return 0; } | ||
| 781 | #endif /* CONFIG_TRACER_SNAPSHOT */ | ||
| 782 | |||
| 699 | static __init void unregister_trigger_traceon_traceoff_cmds(void) | 783 | static __init void unregister_trigger_traceon_traceoff_cmds(void) |
| 700 | { | 784 | { |
| 701 | unregister_event_command(&trigger_traceon_cmd); | 785 | unregister_event_command(&trigger_traceon_cmd); |
| @@ -719,6 +803,7 @@ static __init int register_trigger_traceon_traceoff_cmds(void) | |||
| 719 | __init int register_trigger_cmds(void) | 803 | __init int register_trigger_cmds(void) |
| 720 | { | 804 | { |
| 721 | register_trigger_traceon_traceoff_cmds(); | 805 | register_trigger_traceon_traceoff_cmds(); |
| 806 | register_trigger_snapshot_cmd(); | ||
| 722 | 807 | ||
| 723 | return 0; | 808 | return 0; |
| 724 | } | 809 | } |
