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 | |
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')
-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 | } |