aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorTom Zanussi <tom.zanussi@linux.intel.com>2013-10-24 09:59:28 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-12-21 22:02:16 -0500
commit7862ad1846e994574cb47dc503cc2b1646ea6593 (patch)
treecec348fd60d6f85d1ae772996d0b8241a31d5b35 /kernel/trace
parentf21ecbb35f865a508073c0e73854da469a07f278 (diff)
tracing: Add 'enable_event' and 'disable_event' event trigger commands
Add 'enable_event' and 'disable_event' event_command commands. enable_event and disable_event event triggers are added by the user via these commands in a similar way and using practically the same syntax as the analagous 'enable_event' and 'disable_event' ftrace function commands, but instead of writing to the set_ftrace_filter file, the enable_event and disable_event triggers are written to the per-event 'trigger' files: echo 'enable_event:system:event' > .../othersys/otherevent/trigger echo 'disable_event:system:event' > .../othersys/otherevent/trigger The above commands will enable or disable the 'system:event' trace events whenever the othersys:otherevent events are hit. This also adds a 'count' version that limits the number of times the command will be invoked: echo 'enable_event:system:event:N' > .../othersys/otherevent/trigger echo 'disable_event:system:event:N' > .../othersys/otherevent/trigger Where N is the number of times the command will be invoked. The above commands will will enable or disable the 'system:event' trace events whenever the othersys:otherevent events are hit, but only N times. This also makes the find_event_file() helper function extern, since it's useful to use from other places, such as the event triggers code, so make it accessible. Link: http://lkml.kernel.org/r/f825f3048c3f6b026ee37ae5825f9fc373451828.1382622043.git.tom.zanussi@linux.intel.com Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace.h4
-rw-r--r--kernel/trace/trace_events.c2
-rw-r--r--kernel/trace/trace_events_trigger.c359
3 files changed, 364 insertions, 1 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 50723e5e2b3c..ccbd8104cf99 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1028,6 +1028,10 @@ extern void trace_event_enable_cmd_record(bool enable);
1028extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr); 1028extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
1029extern int event_trace_del_tracer(struct trace_array *tr); 1029extern int event_trace_del_tracer(struct trace_array *tr);
1030 1030
1031extern struct ftrace_event_file *find_event_file(struct trace_array *tr,
1032 const char *system,
1033 const char *event);
1034
1031static inline void *event_file_data(struct file *filp) 1035static inline void *event_file_data(struct file *filp)
1032{ 1036{
1033 return ACCESS_ONCE(file_inode(filp)->i_private); 1037 return ACCESS_ONCE(file_inode(filp)->i_private);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 442775c9dbf3..9a974bd843d4 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1868,7 +1868,7 @@ struct event_probe_data {
1868 bool enable; 1868 bool enable;
1869}; 1869};
1870 1870
1871static struct ftrace_event_file * 1871struct ftrace_event_file *
1872find_event_file(struct trace_array *tr, const char *system, const char *event) 1872find_event_file(struct trace_array *tr, const char *system, const char *event)
1873{ 1873{
1874 struct ftrace_event_file *file; 1874 struct ftrace_event_file *file;
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index a3bd1da90c56..45e48b109d51 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -864,6 +864,364 @@ static __init void unregister_trigger_traceon_traceoff_cmds(void)
864 unregister_event_command(&trigger_traceoff_cmd); 864 unregister_event_command(&trigger_traceoff_cmd);
865} 865}
866 866
867/* Avoid typos */
868#define ENABLE_EVENT_STR "enable_event"
869#define DISABLE_EVENT_STR "disable_event"
870
871struct enable_trigger_data {
872 struct ftrace_event_file *file;
873 bool enable;
874};
875
876static void
877event_enable_trigger(struct event_trigger_data *data)
878{
879 struct enable_trigger_data *enable_data = data->private_data;
880
881 if (enable_data->enable)
882 clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &enable_data->file->flags);
883 else
884 set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &enable_data->file->flags);
885}
886
887static void
888event_enable_count_trigger(struct event_trigger_data *data)
889{
890 struct enable_trigger_data *enable_data = data->private_data;
891
892 if (!data->count)
893 return;
894
895 /* Skip if the event is in a state we want to switch to */
896 if (enable_data->enable == !(enable_data->file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
897 return;
898
899 if (data->count != -1)
900 (data->count)--;
901
902 event_enable_trigger(data);
903}
904
905static int
906event_enable_trigger_print(struct seq_file *m, struct event_trigger_ops *ops,
907 struct event_trigger_data *data)
908{
909 struct enable_trigger_data *enable_data = data->private_data;
910
911 seq_printf(m, "%s:%s:%s",
912 enable_data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
913 enable_data->file->event_call->class->system,
914 enable_data->file->event_call->name);
915
916 if (data->count == -1)
917 seq_puts(m, ":unlimited");
918 else
919 seq_printf(m, ":count=%ld", data->count);
920
921 if (data->filter_str)
922 seq_printf(m, " if %s\n", data->filter_str);
923 else
924 seq_puts(m, "\n");
925
926 return 0;
927}
928
929static void
930event_enable_trigger_free(struct event_trigger_ops *ops,
931 struct event_trigger_data *data)
932{
933 struct enable_trigger_data *enable_data = data->private_data;
934
935 if (WARN_ON_ONCE(data->ref <= 0))
936 return;
937
938 data->ref--;
939 if (!data->ref) {
940 /* Remove the SOFT_MODE flag */
941 trace_event_enable_disable(enable_data->file, 0, 1);
942 module_put(enable_data->file->event_call->mod);
943 trigger_data_free(data);
944 kfree(enable_data);
945 }
946}
947
948static struct event_trigger_ops event_enable_trigger_ops = {
949 .func = event_enable_trigger,
950 .print = event_enable_trigger_print,
951 .init = event_trigger_init,
952 .free = event_enable_trigger_free,
953};
954
955static struct event_trigger_ops event_enable_count_trigger_ops = {
956 .func = event_enable_count_trigger,
957 .print = event_enable_trigger_print,
958 .init = event_trigger_init,
959 .free = event_enable_trigger_free,
960};
961
962static struct event_trigger_ops event_disable_trigger_ops = {
963 .func = event_enable_trigger,
964 .print = event_enable_trigger_print,
965 .init = event_trigger_init,
966 .free = event_enable_trigger_free,
967};
968
969static struct event_trigger_ops event_disable_count_trigger_ops = {
970 .func = event_enable_count_trigger,
971 .print = event_enable_trigger_print,
972 .init = event_trigger_init,
973 .free = event_enable_trigger_free,
974};
975
976static int
977event_enable_trigger_func(struct event_command *cmd_ops,
978 struct ftrace_event_file *file,
979 char *glob, char *cmd, char *param)
980{
981 struct ftrace_event_file *event_enable_file;
982 struct enable_trigger_data *enable_data;
983 struct event_trigger_data *trigger_data;
984 struct event_trigger_ops *trigger_ops;
985 struct trace_array *tr = file->tr;
986 const char *system;
987 const char *event;
988 char *trigger;
989 char *number;
990 bool enable;
991 int ret;
992
993 if (!param)
994 return -EINVAL;
995
996 /* separate the trigger from the filter (s:e:n [if filter]) */
997 trigger = strsep(&param, " \t");
998 if (!trigger)
999 return -EINVAL;
1000
1001 system = strsep(&trigger, ":");
1002 if (!trigger)
1003 return -EINVAL;
1004
1005 event = strsep(&trigger, ":");
1006
1007 ret = -EINVAL;
1008 event_enable_file = find_event_file(tr, system, event);
1009 if (!event_enable_file)
1010 goto out;
1011
1012 enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
1013
1014 trigger_ops = cmd_ops->get_trigger_ops(cmd, trigger);
1015
1016 ret = -ENOMEM;
1017 trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
1018 if (!trigger_data)
1019 goto out;
1020
1021 enable_data = kzalloc(sizeof(*enable_data), GFP_KERNEL);
1022 if (!enable_data) {
1023 kfree(trigger_data);
1024 goto out;
1025 }
1026
1027 trigger_data->count = -1;
1028 trigger_data->ops = trigger_ops;
1029 trigger_data->cmd_ops = cmd_ops;
1030 INIT_LIST_HEAD(&trigger_data->list);
1031 RCU_INIT_POINTER(trigger_data->filter, NULL);
1032
1033 enable_data->enable = enable;
1034 enable_data->file = event_enable_file;
1035 trigger_data->private_data = enable_data;
1036
1037 if (glob[0] == '!') {
1038 cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
1039 kfree(trigger_data);
1040 kfree(enable_data);
1041 ret = 0;
1042 goto out;
1043 }
1044
1045 if (trigger) {
1046 number = strsep(&trigger, ":");
1047
1048 ret = -EINVAL;
1049 if (!strlen(number))
1050 goto out_free;
1051
1052 /*
1053 * We use the callback data field (which is a pointer)
1054 * as our counter.
1055 */
1056 ret = kstrtoul(number, 0, &trigger_data->count);
1057 if (ret)
1058 goto out_free;
1059 }
1060
1061 if (!param) /* if param is non-empty, it's supposed to be a filter */
1062 goto out_reg;
1063
1064 if (!cmd_ops->set_filter)
1065 goto out_reg;
1066
1067 ret = cmd_ops->set_filter(param, trigger_data, file);
1068 if (ret < 0)
1069 goto out_free;
1070
1071 out_reg:
1072 /* Don't let event modules unload while probe registered */
1073 ret = try_module_get(event_enable_file->event_call->mod);
1074 if (!ret) {
1075 ret = -EBUSY;
1076 goto out_free;
1077 }
1078
1079 ret = trace_event_enable_disable(event_enable_file, 1, 1);
1080 if (ret < 0)
1081 goto out_put;
1082 ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
1083 /*
1084 * The above returns on success the # of functions enabled,
1085 * but if it didn't find any functions it returns zero.
1086 * Consider no functions a failure too.
1087 */
1088 if (!ret) {
1089 ret = -ENOENT;
1090 goto out_disable;
1091 } else if (ret < 0)
1092 goto out_disable;
1093 /* Just return zero, not the number of enabled functions */
1094 ret = 0;
1095 out:
1096 return ret;
1097
1098 out_disable:
1099 trace_event_enable_disable(event_enable_file, 0, 1);
1100 out_put:
1101 module_put(event_enable_file->event_call->mod);
1102 out_free:
1103 kfree(trigger_data);
1104 kfree(enable_data);
1105 goto out;
1106}
1107
1108static int event_enable_register_trigger(char *glob,
1109 struct event_trigger_ops *ops,
1110 struct event_trigger_data *data,
1111 struct ftrace_event_file *file)
1112{
1113 struct enable_trigger_data *enable_data = data->private_data;
1114 struct enable_trigger_data *test_enable_data;
1115 struct event_trigger_data *test;
1116 int ret = 0;
1117
1118 list_for_each_entry_rcu(test, &file->triggers, list) {
1119 test_enable_data = test->private_data;
1120 if (test_enable_data &&
1121 (test_enable_data->file == enable_data->file)) {
1122 ret = -EEXIST;
1123 goto out;
1124 }
1125 }
1126
1127 if (data->ops->init) {
1128 ret = data->ops->init(data->ops, data);
1129 if (ret < 0)
1130 goto out;
1131 }
1132
1133 list_add_rcu(&data->list, &file->triggers);
1134 ret++;
1135
1136 if (trace_event_trigger_enable_disable(file, 1) < 0) {
1137 list_del_rcu(&data->list);
1138 ret--;
1139 }
1140out:
1141 return ret;
1142}
1143
1144static void event_enable_unregister_trigger(char *glob,
1145 struct event_trigger_ops *ops,
1146 struct event_trigger_data *test,
1147 struct ftrace_event_file *file)
1148{
1149 struct enable_trigger_data *test_enable_data = test->private_data;
1150 struct enable_trigger_data *enable_data;
1151 struct event_trigger_data *data;
1152 bool unregistered = false;
1153
1154 list_for_each_entry_rcu(data, &file->triggers, list) {
1155 enable_data = data->private_data;
1156 if (enable_data &&
1157 (enable_data->file == test_enable_data->file)) {
1158 unregistered = true;
1159 list_del_rcu(&data->list);
1160 trace_event_trigger_enable_disable(file, 0);
1161 break;
1162 }
1163 }
1164
1165 if (unregistered && data->ops->free)
1166 data->ops->free(data->ops, data);
1167}
1168
1169static struct event_trigger_ops *
1170event_enable_get_trigger_ops(char *cmd, char *param)
1171{
1172 struct event_trigger_ops *ops;
1173 bool enable;
1174
1175 enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
1176
1177 if (enable)
1178 ops = param ? &event_enable_count_trigger_ops :
1179 &event_enable_trigger_ops;
1180 else
1181 ops = param ? &event_disable_count_trigger_ops :
1182 &event_disable_trigger_ops;
1183
1184 return ops;
1185}
1186
1187static struct event_command trigger_enable_cmd = {
1188 .name = ENABLE_EVENT_STR,
1189 .trigger_type = ETT_EVENT_ENABLE,
1190 .func = event_enable_trigger_func,
1191 .reg = event_enable_register_trigger,
1192 .unreg = event_enable_unregister_trigger,
1193 .get_trigger_ops = event_enable_get_trigger_ops,
1194};
1195
1196static struct event_command trigger_disable_cmd = {
1197 .name = DISABLE_EVENT_STR,
1198 .trigger_type = ETT_EVENT_ENABLE,
1199 .func = event_enable_trigger_func,
1200 .reg = event_enable_register_trigger,
1201 .unreg = event_enable_unregister_trigger,
1202 .get_trigger_ops = event_enable_get_trigger_ops,
1203};
1204
1205static __init void unregister_trigger_enable_disable_cmds(void)
1206{
1207 unregister_event_command(&trigger_enable_cmd);
1208 unregister_event_command(&trigger_disable_cmd);
1209}
1210
1211static __init int register_trigger_enable_disable_cmds(void)
1212{
1213 int ret;
1214
1215 ret = register_event_command(&trigger_enable_cmd);
1216 if (WARN_ON(ret < 0))
1217 return ret;
1218 ret = register_event_command(&trigger_disable_cmd);
1219 if (WARN_ON(ret < 0))
1220 unregister_trigger_enable_disable_cmds();
1221
1222 return ret;
1223}
1224
867static __init int register_trigger_traceon_traceoff_cmds(void) 1225static __init int register_trigger_traceon_traceoff_cmds(void)
868{ 1226{
869 int ret; 1227 int ret;
@@ -883,6 +1241,7 @@ __init int register_trigger_cmds(void)
883 register_trigger_traceon_traceoff_cmds(); 1241 register_trigger_traceon_traceoff_cmds();
884 register_trigger_snapshot_cmd(); 1242 register_trigger_snapshot_cmd();
885 register_trigger_stacktrace_cmd(); 1243 register_trigger_stacktrace_cmd();
1244 register_trigger_enable_disable_cmds();
886 1245
887 return 0; 1246 return 0;
888} 1247}