aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorDaniel Wagner <daniel.wagner@bmw-carit.de>2015-08-10 08:35:46 -0400
committerSteven Rostedt <rostedt@goodmis.org>2015-08-11 18:01:06 -0400
commit9f61668073a8d80650622e792aff876db9ca23c6 (patch)
tree4f3416d44b5e350f94a9f46862f896972a569a55 /kernel
parentc93bf928fea22c61f6b5c04786b325c9bfbc0462 (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.c25
-rw-r--r--kernel/trace/trace_events_filter.c54
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 @@
30DEFINE_MUTEX(event_mutex); 30DEFINE_MUTEX(event_mutex);
31 31
32LIST_HEAD(ftrace_events); 32LIST_HEAD(ftrace_events);
33static LIST_HEAD(ftrace_generic_fields);
33static LIST_HEAD(ftrace_common_fields); 34static 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}
145EXPORT_SYMBOL_GPL(trace_define_field); 150EXPORT_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
168static 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
156static int trace_define_common_fields(void) 178static 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. */
256static 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. */
288static 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
255static int filter_pred_none(struct filter_pred *pred, void *event) 299static 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);