diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/Makefile | 1 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 181 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 21 | ||||
| -rw-r--r-- | kernel/trace/trace_events_trigger.c | 278 | ||||
| -rw-r--r-- | kernel/trace/trace_syscalls.c | 4 |
5 files changed, 480 insertions, 5 deletions
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index d7e2068e4b71..1378e84fbe39 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
| @@ -50,6 +50,7 @@ ifeq ($(CONFIG_PERF_EVENTS),y) | |||
| 50 | obj-$(CONFIG_EVENT_TRACING) += trace_event_perf.o | 50 | obj-$(CONFIG_EVENT_TRACING) += trace_event_perf.o |
| 51 | endif | 51 | endif |
| 52 | obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o | 52 | obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o |
| 53 | obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o | ||
| 53 | obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o | 54 | obj-$(CONFIG_KPROBE_EVENT) += trace_kprobe.o |
| 54 | obj-$(CONFIG_TRACEPOINTS) += power-traces.o | 55 | obj-$(CONFIG_TRACEPOINTS) += power-traces.o |
| 55 | ifeq ($(CONFIG_PM_RUNTIME),y) | 56 | ifeq ($(CONFIG_PM_RUNTIME),y) |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index ea189e027b80..9775e518fe77 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -1028,9 +1028,190 @@ extern void trace_event_enable_cmd_record(bool enable); | |||
| 1028 | extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr); | 1028 | extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr); |
| 1029 | extern int event_trace_del_tracer(struct trace_array *tr); | 1029 | extern int event_trace_del_tracer(struct trace_array *tr); |
| 1030 | 1030 | ||
| 1031 | static inline void *event_file_data(struct file *filp) | ||
| 1032 | { | ||
| 1033 | return ACCESS_ONCE(file_inode(filp)->i_private); | ||
| 1034 | } | ||
| 1035 | |||
| 1031 | extern struct mutex event_mutex; | 1036 | extern struct mutex event_mutex; |
| 1032 | extern struct list_head ftrace_events; | 1037 | extern struct list_head ftrace_events; |
| 1033 | 1038 | ||
| 1039 | extern const struct file_operations event_trigger_fops; | ||
| 1040 | |||
| 1041 | extern int register_trigger_cmds(void); | ||
| 1042 | extern void clear_event_triggers(struct trace_array *tr); | ||
| 1043 | |||
| 1044 | struct event_trigger_data { | ||
| 1045 | unsigned long count; | ||
| 1046 | int ref; | ||
| 1047 | struct event_trigger_ops *ops; | ||
| 1048 | struct event_command *cmd_ops; | ||
| 1049 | struct event_filter *filter; | ||
| 1050 | char *filter_str; | ||
| 1051 | void *private_data; | ||
| 1052 | struct list_head list; | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | /** | ||
| 1056 | * struct event_trigger_ops - callbacks for trace event triggers | ||
| 1057 | * | ||
| 1058 | * The methods in this structure provide per-event trigger hooks for | ||
| 1059 | * various trigger operations. | ||
| 1060 | * | ||
| 1061 | * All the methods below, except for @init() and @free(), must be | ||
| 1062 | * implemented. | ||
| 1063 | * | ||
| 1064 | * @func: The trigger 'probe' function called when the triggering | ||
| 1065 | * event occurs. The data passed into this callback is the data | ||
| 1066 | * that was supplied to the event_command @reg() function that | ||
| 1067 | * registered the trigger (see struct event_command). | ||
| 1068 | * | ||
| 1069 | * @init: An optional initialization function called for the trigger | ||
| 1070 | * when the trigger is registered (via the event_command reg() | ||
| 1071 | * function). This can be used to perform per-trigger | ||
| 1072 | * initialization such as incrementing a per-trigger reference | ||
| 1073 | * count, for instance. This is usually implemented by the | ||
| 1074 | * generic utility function @event_trigger_init() (see | ||
| 1075 | * trace_event_triggers.c). | ||
| 1076 | * | ||
| 1077 | * @free: An optional de-initialization function called for the | ||
| 1078 | * trigger when the trigger is unregistered (via the | ||
| 1079 | * event_command @reg() function). This can be used to perform | ||
| 1080 | * per-trigger de-initialization such as decrementing a | ||
| 1081 | * per-trigger reference count and freeing corresponding trigger | ||
| 1082 | * data, for instance. This is usually implemented by the | ||
| 1083 | * generic utility function @event_trigger_free() (see | ||
| 1084 | * trace_event_triggers.c). | ||
| 1085 | * | ||
| 1086 | * @print: The callback function invoked to have the trigger print | ||
| 1087 | * itself. This is usually implemented by a wrapper function | ||
| 1088 | * that calls the generic utility function @event_trigger_print() | ||
| 1089 | * (see trace_event_triggers.c). | ||
| 1090 | */ | ||
| 1091 | struct event_trigger_ops { | ||
| 1092 | void (*func)(struct event_trigger_data *data); | ||
| 1093 | int (*init)(struct event_trigger_ops *ops, | ||
| 1094 | struct event_trigger_data *data); | ||
| 1095 | void (*free)(struct event_trigger_ops *ops, | ||
| 1096 | struct event_trigger_data *data); | ||
| 1097 | int (*print)(struct seq_file *m, | ||
| 1098 | struct event_trigger_ops *ops, | ||
| 1099 | struct event_trigger_data *data); | ||
| 1100 | }; | ||
| 1101 | |||
| 1102 | /** | ||
| 1103 | * struct event_command - callbacks and data members for event commands | ||
| 1104 | * | ||
| 1105 | * Event commands are invoked by users by writing the command name | ||
| 1106 | * into the 'trigger' file associated with a trace event. The | ||
| 1107 | * parameters associated with a specific invocation of an event | ||
| 1108 | * command are used to create an event trigger instance, which is | ||
| 1109 | * added to the list of trigger instances associated with that trace | ||
| 1110 | * event. When the event is hit, the set of triggers associated with | ||
| 1111 | * that event is invoked. | ||
| 1112 | * | ||
| 1113 | * The data members in this structure provide per-event command data | ||
| 1114 | * for various event commands. | ||
| 1115 | * | ||
| 1116 | * All the data members below, except for @post_trigger, must be set | ||
| 1117 | * for each event command. | ||
| 1118 | * | ||
| 1119 | * @name: The unique name that identifies the event command. This is | ||
| 1120 | * the name used when setting triggers via trigger files. | ||
| 1121 | * | ||
| 1122 | * @trigger_type: A unique id that identifies the event command | ||
| 1123 | * 'type'. This value has two purposes, the first to ensure that | ||
| 1124 | * only one trigger of the same type can be set at a given time | ||
| 1125 | * for a particular event e.g. it doesn't make sense to have both | ||
| 1126 | * a traceon and traceoff trigger attached to a single event at | ||
| 1127 | * the same time, so traceon and traceoff have the same type | ||
| 1128 | * though they have different names. The @trigger_type value is | ||
| 1129 | * also used as a bit value for deferring the actual trigger | ||
| 1130 | * action until after the current event is finished. Some | ||
| 1131 | * commands need to do this if they themselves log to the trace | ||
| 1132 | * buffer (see the @post_trigger() member below). @trigger_type | ||
| 1133 | * values are defined by adding new values to the trigger_type | ||
| 1134 | * enum in include/linux/ftrace_event.h. | ||
| 1135 | * | ||
| 1136 | * @post_trigger: A flag that says whether or not this command needs | ||
| 1137 | * to have its action delayed until after the current event has | ||
| 1138 | * been closed. Some triggers need to avoid being invoked while | ||
| 1139 | * an event is currently in the process of being logged, since | ||
| 1140 | * the trigger may itself log data into the trace buffer. Thus | ||
| 1141 | * we make sure the current event is committed before invoking | ||
| 1142 | * those triggers. To do that, the trigger invocation is split | ||
| 1143 | * in two - the first part checks the filter using the current | ||
| 1144 | * trace record; if a command has the @post_trigger flag set, it | ||
| 1145 | * sets a bit for itself in the return value, otherwise it | ||
| 1146 | * directly invokes the trigger. Once all commands have been | ||
| 1147 | * either invoked or set their return flag, the current record is | ||
| 1148 | * either committed or discarded. At that point, if any commands | ||
| 1149 | * have deferred their triggers, those commands are finally | ||
| 1150 | * invoked following the close of the current event. In other | ||
| 1151 | * words, if the event_trigger_ops @func() probe implementation | ||
| 1152 | * itself logs to the trace buffer, this flag should be set, | ||
| 1153 | * otherwise it can be left unspecified. | ||
| 1154 | * | ||
| 1155 | * All the methods below, except for @set_filter(), must be | ||
| 1156 | * implemented. | ||
| 1157 | * | ||
| 1158 | * @func: The callback function responsible for parsing and | ||
| 1159 | * registering the trigger written to the 'trigger' file by the | ||
| 1160 | * user. It allocates the trigger instance and registers it with | ||
| 1161 | * the appropriate trace event. It makes use of the other | ||
| 1162 | * event_command callback functions to orchestrate this, and is | ||
| 1163 | * usually implemented by the generic utility function | ||
| 1164 | * @event_trigger_callback() (see trace_event_triggers.c). | ||
| 1165 | * | ||
| 1166 | * @reg: Adds the trigger to the list of triggers associated with the | ||
| 1167 | * event, and enables the event trigger itself, after | ||
| 1168 | * initializing it (via the event_trigger_ops @init() function). | ||
| 1169 | * This is also where commands can use the @trigger_type value to | ||
| 1170 | * make the decision as to whether or not multiple instances of | ||
| 1171 | * the trigger should be allowed. This is usually implemented by | ||
| 1172 | * the generic utility function @register_trigger() (see | ||
| 1173 | * trace_event_triggers.c). | ||
| 1174 | * | ||
| 1175 | * @unreg: Removes the trigger from the list of triggers associated | ||
| 1176 | * with the event, and disables the event trigger itself, after | ||
| 1177 | * initializing it (via the event_trigger_ops @free() function). | ||
| 1178 | * This is usually implemented by the generic utility function | ||
| 1179 | * @unregister_trigger() (see trace_event_triggers.c). | ||
| 1180 | * | ||
| 1181 | * @set_filter: An optional function called to parse and set a filter | ||
| 1182 | * for the trigger. If no @set_filter() method is set for the | ||
| 1183 | * event command, filters set by the user for the command will be | ||
| 1184 | * ignored. This is usually implemented by the generic utility | ||
| 1185 | * function @set_trigger_filter() (see trace_event_triggers.c). | ||
| 1186 | * | ||
| 1187 | * @get_trigger_ops: The callback function invoked to retrieve the | ||
| 1188 | * event_trigger_ops implementation associated with the command. | ||
| 1189 | */ | ||
| 1190 | struct event_command { | ||
| 1191 | struct list_head list; | ||
| 1192 | char *name; | ||
| 1193 | enum event_trigger_type trigger_type; | ||
| 1194 | bool post_trigger; | ||
| 1195 | int (*func)(struct event_command *cmd_ops, | ||
| 1196 | struct ftrace_event_file *file, | ||
| 1197 | char *glob, char *cmd, char *params); | ||
| 1198 | int (*reg)(char *glob, | ||
| 1199 | struct event_trigger_ops *ops, | ||
| 1200 | struct event_trigger_data *data, | ||
| 1201 | struct ftrace_event_file *file); | ||
| 1202 | void (*unreg)(char *glob, | ||
| 1203 | struct event_trigger_ops *ops, | ||
| 1204 | struct event_trigger_data *data, | ||
| 1205 | struct ftrace_event_file *file); | ||
| 1206 | int (*set_filter)(char *filter_str, | ||
| 1207 | struct event_trigger_data *data, | ||
| 1208 | struct ftrace_event_file *file); | ||
| 1209 | struct event_trigger_ops *(*get_trigger_ops)(char *cmd, char *param); | ||
| 1210 | }; | ||
| 1211 | |||
| 1212 | extern int trace_event_enable_disable(struct ftrace_event_file *file, | ||
| 1213 | int enable, int soft_disable); | ||
| 1214 | |||
| 1034 | extern const char *__start___trace_bprintk_fmt[]; | 1215 | extern const char *__start___trace_bprintk_fmt[]; |
| 1035 | extern const char *__stop___trace_bprintk_fmt[]; | 1216 | extern const char *__stop___trace_bprintk_fmt[]; |
| 1036 | 1217 | ||
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index a11800ae96de..442775c9dbf3 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -342,6 +342,12 @@ static int __ftrace_event_enable_disable(struct ftrace_event_file *file, | |||
| 342 | return ret; | 342 | return ret; |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | int trace_event_enable_disable(struct ftrace_event_file *file, | ||
| 346 | int enable, int soft_disable) | ||
| 347 | { | ||
| 348 | return __ftrace_event_enable_disable(file, enable, soft_disable); | ||
| 349 | } | ||
| 350 | |||
| 345 | static int ftrace_event_enable_disable(struct ftrace_event_file *file, | 351 | static int ftrace_event_enable_disable(struct ftrace_event_file *file, |
| 346 | int enable) | 352 | int enable) |
| 347 | { | 353 | { |
| @@ -421,11 +427,6 @@ static void remove_subsystem(struct ftrace_subsystem_dir *dir) | |||
| 421 | } | 427 | } |
| 422 | } | 428 | } |
| 423 | 429 | ||
| 424 | static void *event_file_data(struct file *filp) | ||
| 425 | { | ||
| 426 | return ACCESS_ONCE(file_inode(filp)->i_private); | ||
| 427 | } | ||
| 428 | |||
| 429 | static void remove_event_file_dir(struct ftrace_event_file *file) | 430 | static void remove_event_file_dir(struct ftrace_event_file *file) |
| 430 | { | 431 | { |
| 431 | struct dentry *dir = file->dir; | 432 | struct dentry *dir = file->dir; |
| @@ -1549,6 +1550,9 @@ event_create_dir(struct dentry *parent, struct ftrace_event_file *file) | |||
| 1549 | trace_create_file("filter", 0644, file->dir, file, | 1550 | trace_create_file("filter", 0644, file->dir, file, |
| 1550 | &ftrace_event_filter_fops); | 1551 | &ftrace_event_filter_fops); |
| 1551 | 1552 | ||
| 1553 | trace_create_file("trigger", 0644, file->dir, file, | ||
| 1554 | &event_trigger_fops); | ||
| 1555 | |||
| 1552 | trace_create_file("format", 0444, file->dir, call, | 1556 | trace_create_file("format", 0444, file->dir, call, |
| 1553 | &ftrace_event_format_fops); | 1557 | &ftrace_event_format_fops); |
| 1554 | 1558 | ||
| @@ -1645,6 +1649,8 @@ trace_create_new_event(struct ftrace_event_call *call, | |||
| 1645 | file->event_call = call; | 1649 | file->event_call = call; |
| 1646 | file->tr = tr; | 1650 | file->tr = tr; |
| 1647 | atomic_set(&file->sm_ref, 0); | 1651 | atomic_set(&file->sm_ref, 0); |
| 1652 | atomic_set(&file->tm_ref, 0); | ||
| 1653 | INIT_LIST_HEAD(&file->triggers); | ||
| 1648 | list_add(&file->list, &tr->events); | 1654 | list_add(&file->list, &tr->events); |
| 1649 | 1655 | ||
| 1650 | return file; | 1656 | return file; |
| @@ -2311,6 +2317,9 @@ int event_trace_del_tracer(struct trace_array *tr) | |||
| 2311 | { | 2317 | { |
| 2312 | mutex_lock(&event_mutex); | 2318 | mutex_lock(&event_mutex); |
| 2313 | 2319 | ||
| 2320 | /* Disable any event triggers and associated soft-disabled events */ | ||
| 2321 | clear_event_triggers(tr); | ||
| 2322 | |||
| 2314 | /* Disable any running events */ | 2323 | /* Disable any running events */ |
| 2315 | __ftrace_set_clr_event_nolock(tr, NULL, NULL, NULL, 0); | 2324 | __ftrace_set_clr_event_nolock(tr, NULL, NULL, NULL, 0); |
| 2316 | 2325 | ||
| @@ -2377,6 +2386,8 @@ static __init int event_trace_enable(void) | |||
| 2377 | 2386 | ||
| 2378 | register_event_cmds(); | 2387 | register_event_cmds(); |
| 2379 | 2388 | ||
| 2389 | register_trigger_cmds(); | ||
| 2390 | |||
| 2380 | return 0; | 2391 | return 0; |
| 2381 | } | 2392 | } |
| 2382 | 2393 | ||
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c new file mode 100644 index 000000000000..60a6a6d66dc0 --- /dev/null +++ b/kernel/trace/trace_events_trigger.c | |||
| @@ -0,0 +1,278 @@ | |||
| 1 | /* | ||
| 2 | * trace_events_trigger - trace event triggers | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | * | ||
| 18 | * Copyright (C) 2013 Tom Zanussi <tom.zanussi@linux.intel.com> | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/ctype.h> | ||
| 23 | #include <linux/mutex.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | |||
| 26 | #include "trace.h" | ||
| 27 | |||
| 28 | static LIST_HEAD(trigger_commands); | ||
| 29 | static DEFINE_MUTEX(trigger_cmd_mutex); | ||
| 30 | |||
| 31 | /** | ||
| 32 | * event_triggers_call - Call triggers associated with a trace event | ||
| 33 | * @file: The ftrace_event_file associated with the event | ||
| 34 | * | ||
| 35 | * For each trigger associated with an event, invoke the trigger | ||
| 36 | * function registered with the associated trigger command. | ||
| 37 | * | ||
| 38 | * Called from tracepoint handlers (with rcu_read_lock_sched() held). | ||
| 39 | * | ||
| 40 | * Return: an enum event_trigger_type value containing a set bit for | ||
| 41 | * any trigger that should be deferred, ETT_NONE if nothing to defer. | ||
| 42 | */ | ||
| 43 | void event_triggers_call(struct ftrace_event_file *file) | ||
| 44 | { | ||
| 45 | struct event_trigger_data *data; | ||
| 46 | |||
| 47 | if (list_empty(&file->triggers)) | ||
| 48 | return; | ||
| 49 | |||
| 50 | list_for_each_entry_rcu(data, &file->triggers, list) | ||
| 51 | data->ops->func(data); | ||
| 52 | } | ||
| 53 | EXPORT_SYMBOL_GPL(event_triggers_call); | ||
| 54 | |||
| 55 | static void *trigger_next(struct seq_file *m, void *t, loff_t *pos) | ||
| 56 | { | ||
| 57 | struct ftrace_event_file *event_file = event_file_data(m->private); | ||
| 58 | |||
| 59 | return seq_list_next(t, &event_file->triggers, pos); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void *trigger_start(struct seq_file *m, loff_t *pos) | ||
| 63 | { | ||
| 64 | struct ftrace_event_file *event_file; | ||
| 65 | |||
| 66 | /* ->stop() is called even if ->start() fails */ | ||
| 67 | mutex_lock(&event_mutex); | ||
| 68 | event_file = event_file_data(m->private); | ||
| 69 | if (unlikely(!event_file)) | ||
| 70 | return ERR_PTR(-ENODEV); | ||
| 71 | |||
| 72 | return seq_list_start(&event_file->triggers, *pos); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void trigger_stop(struct seq_file *m, void *t) | ||
| 76 | { | ||
| 77 | mutex_unlock(&event_mutex); | ||
| 78 | } | ||
| 79 | |||
| 80 | static int trigger_show(struct seq_file *m, void *v) | ||
| 81 | { | ||
| 82 | struct event_trigger_data *data; | ||
| 83 | |||
| 84 | data = list_entry(v, struct event_trigger_data, list); | ||
| 85 | data->ops->print(m, data->ops, data); | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static const struct seq_operations event_triggers_seq_ops = { | ||
| 91 | .start = trigger_start, | ||
| 92 | .next = trigger_next, | ||
| 93 | .stop = trigger_stop, | ||
| 94 | .show = trigger_show, | ||
| 95 | }; | ||
| 96 | |||
| 97 | static int event_trigger_regex_open(struct inode *inode, struct file *file) | ||
| 98 | { | ||
| 99 | int ret = 0; | ||
| 100 | |||
| 101 | mutex_lock(&event_mutex); | ||
| 102 | |||
| 103 | if (unlikely(!event_file_data(file))) { | ||
| 104 | mutex_unlock(&event_mutex); | ||
| 105 | return -ENODEV; | ||
| 106 | } | ||
| 107 | |||
| 108 | if (file->f_mode & FMODE_READ) { | ||
| 109 | ret = seq_open(file, &event_triggers_seq_ops); | ||
| 110 | if (!ret) { | ||
| 111 | struct seq_file *m = file->private_data; | ||
| 112 | m->private = file; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | mutex_unlock(&event_mutex); | ||
| 117 | |||
| 118 | return ret; | ||
| 119 | } | ||
| 120 | |||
| 121 | static int trigger_process_regex(struct ftrace_event_file *file, char *buff) | ||
| 122 | { | ||
| 123 | char *command, *next = buff; | ||
| 124 | struct event_command *p; | ||
| 125 | int ret = -EINVAL; | ||
| 126 | |||
| 127 | command = strsep(&next, ": \t"); | ||
| 128 | command = (command[0] != '!') ? command : command + 1; | ||
| 129 | |||
| 130 | mutex_lock(&trigger_cmd_mutex); | ||
| 131 | list_for_each_entry(p, &trigger_commands, list) { | ||
| 132 | if (strcmp(p->name, command) == 0) { | ||
| 133 | ret = p->func(p, file, buff, command, next); | ||
| 134 | goto out_unlock; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | out_unlock: | ||
| 138 | mutex_unlock(&trigger_cmd_mutex); | ||
| 139 | |||
| 140 | return ret; | ||
| 141 | } | ||
| 142 | |||
| 143 | static ssize_t event_trigger_regex_write(struct file *file, | ||
| 144 | const char __user *ubuf, | ||
| 145 | size_t cnt, loff_t *ppos) | ||
| 146 | { | ||
| 147 | struct ftrace_event_file *event_file; | ||
| 148 | ssize_t ret; | ||
| 149 | char *buf; | ||
| 150 | |||
| 151 | if (!cnt) | ||
| 152 | return 0; | ||
| 153 | |||
| 154 | if (cnt >= PAGE_SIZE) | ||
| 155 | return -EINVAL; | ||
| 156 | |||
| 157 | buf = (char *)__get_free_page(GFP_TEMPORARY); | ||
| 158 | if (!buf) | ||
| 159 | return -ENOMEM; | ||
| 160 | |||
| 161 | if (copy_from_user(buf, ubuf, cnt)) { | ||
| 162 | free_page((unsigned long)buf); | ||
| 163 | return -EFAULT; | ||
| 164 | } | ||
| 165 | buf[cnt] = '\0'; | ||
| 166 | strim(buf); | ||
| 167 | |||
| 168 | mutex_lock(&event_mutex); | ||
| 169 | event_file = event_file_data(file); | ||
| 170 | if (unlikely(!event_file)) { | ||
| 171 | mutex_unlock(&event_mutex); | ||
| 172 | free_page((unsigned long)buf); | ||
| 173 | return -ENODEV; | ||
| 174 | } | ||
| 175 | ret = trigger_process_regex(event_file, buf); | ||
| 176 | mutex_unlock(&event_mutex); | ||
| 177 | |||
| 178 | free_page((unsigned long)buf); | ||
| 179 | if (ret < 0) | ||
| 180 | goto out; | ||
| 181 | |||
| 182 | *ppos += cnt; | ||
| 183 | ret = cnt; | ||
| 184 | out: | ||
| 185 | return ret; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int event_trigger_regex_release(struct inode *inode, struct file *file) | ||
| 189 | { | ||
| 190 | mutex_lock(&event_mutex); | ||
| 191 | |||
| 192 | if (file->f_mode & FMODE_READ) | ||
| 193 | seq_release(inode, file); | ||
| 194 | |||
| 195 | mutex_unlock(&event_mutex); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static ssize_t | ||
| 201 | event_trigger_write(struct file *filp, const char __user *ubuf, | ||
| 202 | size_t cnt, loff_t *ppos) | ||
| 203 | { | ||
| 204 | return event_trigger_regex_write(filp, ubuf, cnt, ppos); | ||
| 205 | } | ||
| 206 | |||
| 207 | static int | ||
| 208 | event_trigger_open(struct inode *inode, struct file *filp) | ||
| 209 | { | ||
| 210 | return event_trigger_regex_open(inode, filp); | ||
| 211 | } | ||
| 212 | |||
| 213 | static int | ||
| 214 | event_trigger_release(struct inode *inode, struct file *file) | ||
| 215 | { | ||
| 216 | return event_trigger_regex_release(inode, file); | ||
| 217 | } | ||
| 218 | |||
| 219 | const struct file_operations event_trigger_fops = { | ||
| 220 | .open = event_trigger_open, | ||
| 221 | .read = seq_read, | ||
| 222 | .write = event_trigger_write, | ||
| 223 | .llseek = ftrace_filter_lseek, | ||
| 224 | .release = event_trigger_release, | ||
| 225 | }; | ||
| 226 | |||
| 227 | static int trace_event_trigger_enable_disable(struct ftrace_event_file *file, | ||
| 228 | int trigger_enable) | ||
| 229 | { | ||
| 230 | int ret = 0; | ||
| 231 | |||
| 232 | if (trigger_enable) { | ||
| 233 | if (atomic_inc_return(&file->tm_ref) > 1) | ||
| 234 | return ret; | ||
| 235 | set_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &file->flags); | ||
| 236 | ret = trace_event_enable_disable(file, 1, 1); | ||
| 237 | } else { | ||
| 238 | if (atomic_dec_return(&file->tm_ref) > 0) | ||
| 239 | return ret; | ||
| 240 | clear_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &file->flags); | ||
| 241 | ret = trace_event_enable_disable(file, 0, 1); | ||
| 242 | } | ||
| 243 | |||
| 244 | return ret; | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * clear_event_triggers - Clear all triggers associated with a trace array | ||
| 249 | * @tr: The trace array to clear | ||
| 250 | * | ||
| 251 | * For each trigger, the triggering event has its tm_ref decremented | ||
| 252 | * via trace_event_trigger_enable_disable(), and any associated event | ||
| 253 | * (in the case of enable/disable_event triggers) will have its sm_ref | ||
| 254 | * decremented via free()->trace_event_enable_disable(). That | ||
| 255 | * combination effectively reverses the soft-mode/trigger state added | ||
| 256 | * by trigger registration. | ||
| 257 | * | ||
| 258 | * Must be called with event_mutex held. | ||
| 259 | */ | ||
| 260 | void | ||
| 261 | clear_event_triggers(struct trace_array *tr) | ||
| 262 | { | ||
| 263 | struct ftrace_event_file *file; | ||
| 264 | |||
| 265 | list_for_each_entry(file, &tr->events, list) { | ||
| 266 | struct event_trigger_data *data; | ||
| 267 | list_for_each_entry_rcu(data, &file->triggers, list) { | ||
| 268 | trace_event_trigger_enable_disable(file, 0); | ||
| 269 | if (data->ops->free) | ||
| 270 | data->ops->free(data->ops, data); | ||
| 271 | } | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | __init int register_trigger_cmds(void) | ||
| 276 | { | ||
| 277 | return 0; | ||
| 278 | } | ||
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index ea90eb5f6f17..936ec3960335 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
| @@ -321,6 +321,8 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
| 321 | if (!ftrace_file) | 321 | if (!ftrace_file) |
| 322 | return; | 322 | return; |
| 323 | 323 | ||
| 324 | if (test_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &ftrace_file->flags)) | ||
| 325 | event_triggers_call(ftrace_file); | ||
| 324 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) | 326 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) |
| 325 | return; | 327 | return; |
| 326 | 328 | ||
| @@ -369,6 +371,8 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | |||
| 369 | if (!ftrace_file) | 371 | if (!ftrace_file) |
| 370 | return; | 372 | return; |
| 371 | 373 | ||
| 374 | if (test_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &ftrace_file->flags)) | ||
| 375 | event_triggers_call(ftrace_file); | ||
| 372 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) | 376 | if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) |
| 373 | return; | 377 | return; |
| 374 | 378 | ||
