diff options
author | Daniel Wagner <daniel.wagner@bmw-carit.de> | 2015-08-10 08:35:46 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2015-08-11 18:01:06 -0400 |
commit | 9f61668073a8d80650622e792aff876db9ca23c6 (patch) | |
tree | 4f3416d44b5e350f94a9f46862f896972a569a55 /kernel | |
parent | c93bf928fea22c61f6b5c04786b325c9bfbc0462 (diff) |
tracing: Allow triggers to filter for CPU ids and process names
By extending the filter rules by more generic fields
we can write triggers filters like
echo 'stacktrace if cpu == 1' > \
/sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger
or
echo 'stacktrace if comm == sshd' > \
/sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger
CPU and COMM are not part of struct trace_entry. We could add the two
new fields to ftrace_common_field list and fix up all depending
sides. But that looks pretty ugly. Another thing I would like to
avoid that the 'format' file contents changes.
All this can be avoided by introducing another list which contains
non field members of struct trace_entry.
Link: http://lkml.kernel.org/r/1439210146-24707-1-git-send-email-daniel.wagner@bmw-carit.de
Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_events.c | 25 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 54 |
2 files changed, 77 insertions, 2 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 404a372ad85a..7ca09cdc20c2 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -30,6 +30,7 @@ | |||
30 | DEFINE_MUTEX(event_mutex); | 30 | DEFINE_MUTEX(event_mutex); |
31 | 31 | ||
32 | LIST_HEAD(ftrace_events); | 32 | LIST_HEAD(ftrace_events); |
33 | static LIST_HEAD(ftrace_generic_fields); | ||
33 | static LIST_HEAD(ftrace_common_fields); | 34 | static LIST_HEAD(ftrace_common_fields); |
34 | 35 | ||
35 | #define GFP_TRACE (GFP_KERNEL | __GFP_ZERO) | 36 | #define GFP_TRACE (GFP_KERNEL | __GFP_ZERO) |
@@ -94,6 +95,10 @@ trace_find_event_field(struct trace_event_call *call, char *name) | |||
94 | struct ftrace_event_field *field; | 95 | struct ftrace_event_field *field; |
95 | struct list_head *head; | 96 | struct list_head *head; |
96 | 97 | ||
98 | field = __find_event_field(&ftrace_generic_fields, name); | ||
99 | if (field) | ||
100 | return field; | ||
101 | |||
97 | field = __find_event_field(&ftrace_common_fields, name); | 102 | field = __find_event_field(&ftrace_common_fields, name); |
98 | if (field) | 103 | if (field) |
99 | return field; | 104 | return field; |
@@ -144,6 +149,13 @@ int trace_define_field(struct trace_event_call *call, const char *type, | |||
144 | } | 149 | } |
145 | EXPORT_SYMBOL_GPL(trace_define_field); | 150 | EXPORT_SYMBOL_GPL(trace_define_field); |
146 | 151 | ||
152 | #define __generic_field(type, item, filter_type) \ | ||
153 | ret = __trace_define_field(&ftrace_generic_fields, #type, \ | ||
154 | #item, 0, 0, is_signed_type(type), \ | ||
155 | filter_type); \ | ||
156 | if (ret) \ | ||
157 | return ret; | ||
158 | |||
147 | #define __common_field(type, item) \ | 159 | #define __common_field(type, item) \ |
148 | ret = __trace_define_field(&ftrace_common_fields, #type, \ | 160 | ret = __trace_define_field(&ftrace_common_fields, #type, \ |
149 | "common_" #item, \ | 161 | "common_" #item, \ |
@@ -153,6 +165,16 @@ EXPORT_SYMBOL_GPL(trace_define_field); | |||
153 | if (ret) \ | 165 | if (ret) \ |
154 | return ret; | 166 | return ret; |
155 | 167 | ||
168 | static int trace_define_generic_fields(void) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | __generic_field(int, cpu, FILTER_OTHER); | ||
173 | __generic_field(char *, comm, FILTER_PTR_STRING); | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
156 | static int trace_define_common_fields(void) | 178 | static int trace_define_common_fields(void) |
157 | { | 179 | { |
158 | int ret; | 180 | int ret; |
@@ -2671,6 +2693,9 @@ static __init int event_trace_init(void) | |||
2671 | if (!entry) | 2693 | if (!entry) |
2672 | pr_warn("Could not create tracefs 'available_events' entry\n"); | 2694 | pr_warn("Could not create tracefs 'available_events' entry\n"); |
2673 | 2695 | ||
2696 | if (trace_define_generic_fields()) | ||
2697 | pr_warn("tracing: Failed to allocated generic fields"); | ||
2698 | |||
2674 | if (trace_define_common_fields()) | 2699 | if (trace_define_common_fields()) |
2675 | pr_warn("tracing: Failed to allocate common fields"); | 2700 | pr_warn("tracing: Failed to allocate common fields"); |
2676 | 2701 | ||
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index d81d6f302b14..bd1bf184c5c9 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -252,6 +252,50 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event) | |||
252 | return match; | 252 | return match; |
253 | } | 253 | } |
254 | 254 | ||
255 | /* Filter predicate for CPUs. */ | ||
256 | static int filter_pred_cpu(struct filter_pred *pred, void *event) | ||
257 | { | ||
258 | int cpu, cmp; | ||
259 | int match = 0; | ||
260 | |||
261 | cpu = raw_smp_processor_id(); | ||
262 | cmp = pred->val; | ||
263 | |||
264 | switch (pred->op) { | ||
265 | case OP_EQ: | ||
266 | match = cpu == cmp; | ||
267 | break; | ||
268 | case OP_LT: | ||
269 | match = cpu < cmp; | ||
270 | break; | ||
271 | case OP_LE: | ||
272 | match = cpu <= cmp; | ||
273 | break; | ||
274 | case OP_GT: | ||
275 | match = cpu > cmp; | ||
276 | break; | ||
277 | case OP_GE: | ||
278 | match = cpu >= cmp; | ||
279 | break; | ||
280 | default: | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | return !!match == !pred->not; | ||
285 | } | ||
286 | |||
287 | /* Filter predicate for COMM. */ | ||
288 | static int filter_pred_comm(struct filter_pred *pred, void *event) | ||
289 | { | ||
290 | int cmp, match; | ||
291 | |||
292 | cmp = pred->regex.match(current->comm, &pred->regex, | ||
293 | pred->regex.field_len); | ||
294 | match = cmp ^ pred->not; | ||
295 | |||
296 | return match; | ||
297 | } | ||
298 | |||
255 | static int filter_pred_none(struct filter_pred *pred, void *event) | 299 | static int filter_pred_none(struct filter_pred *pred, void *event) |
256 | { | 300 | { |
257 | return 0; | 301 | return 0; |
@@ -1002,7 +1046,10 @@ static int init_pred(struct filter_parse_state *ps, | |||
1002 | if (is_string_field(field)) { | 1046 | if (is_string_field(field)) { |
1003 | filter_build_regex(pred); | 1047 | filter_build_regex(pred); |
1004 | 1048 | ||
1005 | if (field->filter_type == FILTER_STATIC_STRING) { | 1049 | if (!strcmp(field->name, "comm")) { |
1050 | fn = filter_pred_comm; | ||
1051 | pred->regex.field_len = TASK_COMM_LEN; | ||
1052 | } else if (field->filter_type == FILTER_STATIC_STRING) { | ||
1006 | fn = filter_pred_string; | 1053 | fn = filter_pred_string; |
1007 | pred->regex.field_len = field->size; | 1054 | pred->regex.field_len = field->size; |
1008 | } else if (field->filter_type == FILTER_DYN_STRING) | 1055 | } else if (field->filter_type == FILTER_DYN_STRING) |
@@ -1025,7 +1072,10 @@ static int init_pred(struct filter_parse_state *ps, | |||
1025 | } | 1072 | } |
1026 | pred->val = val; | 1073 | pred->val = val; |
1027 | 1074 | ||
1028 | fn = select_comparison_fn(pred->op, field->size, | 1075 | if (!strcmp(field->name, "cpu")) |
1076 | fn = filter_pred_cpu; | ||
1077 | else | ||
1078 | fn = select_comparison_fn(pred->op, field->size, | ||
1029 | field->is_signed); | 1079 | field->is_signed); |
1030 | if (!fn) { | 1080 | if (!fn) { |
1031 | parse_error(ps, FILT_ERR_INVALID_OP, 0); | 1081 | parse_error(ps, FILT_ERR_INVALID_OP, 0); |