aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-12-02 11:55:36 -0500
committerSteven Rostedt <rostedt@goodmis.org>2014-12-03 10:00:13 -0500
commite12c09cf3087b5a184ffeb55ca368e8aa436a3a2 (patch)
treeedaefaee5f456a84484ccf40ae8b84f41228253f /kernel/trace
parent6a06bdbf7f9c669743f58084991ba280f2925586 (diff)
tracing: Add NOT to filtering logic
Ted noticed that he could not filter on an event for a bit being cleared. That's because the filtering logic only tests event fields with a limited number of comparisons which, for bit logic, only include "&", which can test if a bit is set, but there's no good way to see if a bit is clear. This adds a way to do: !(field & 2048) Which returns true if the bit is not set, and false otherwise. Note, currently !(field1 == 10 && field2 == 15) is not supported. That is, the 'not' only works for direct comparisons, not for the AND and OR logic. Link: http://lkml.kernel.org/r/20141202021912.GA29096@thunk.org Link: http://lkml.kernel.org/r/20141202120430.71979060@gandalf.local.home Acked-by: Alexei Starovoitov <ast@plumgrid.com> Suggested-by: "Theodore Ts'o" <tytso@mit.edu> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_events_filter.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 7a8c1528e141..e6a33db83856 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -45,6 +45,7 @@ enum filter_op_ids
45 OP_GT, 45 OP_GT,
46 OP_GE, 46 OP_GE,
47 OP_BAND, 47 OP_BAND,
48 OP_NOT,
48 OP_NONE, 49 OP_NONE,
49 OP_OPEN_PAREN, 50 OP_OPEN_PAREN,
50}; 51};
@@ -67,6 +68,7 @@ static struct filter_op filter_ops[] = {
67 { OP_GT, ">", 5 }, 68 { OP_GT, ">", 5 },
68 { OP_GE, ">=", 5 }, 69 { OP_GE, ">=", 5 },
69 { OP_BAND, "&", 6 }, 70 { OP_BAND, "&", 6 },
71 { OP_NOT, "!", 6 },
70 { OP_NONE, "OP_NONE", 0 }, 72 { OP_NONE, "OP_NONE", 0 },
71 { OP_OPEN_PAREN, "(", 0 }, 73 { OP_OPEN_PAREN, "(", 0 },
72}; 74};
@@ -85,6 +87,7 @@ enum {
85 FILT_ERR_MISSING_FIELD, 87 FILT_ERR_MISSING_FIELD,
86 FILT_ERR_INVALID_FILTER, 88 FILT_ERR_INVALID_FILTER,
87 FILT_ERR_IP_FIELD_ONLY, 89 FILT_ERR_IP_FIELD_ONLY,
90 FILT_ERR_ILLEGAL_NOT_OP,
88}; 91};
89 92
90static char *err_text[] = { 93static char *err_text[] = {
@@ -101,6 +104,7 @@ static char *err_text[] = {
101 "Missing field name and/or value", 104 "Missing field name and/or value",
102 "Meaningless filter expression", 105 "Meaningless filter expression",
103 "Only 'ip' field is supported for function trace", 106 "Only 'ip' field is supported for function trace",
107 "Illegal use of '!'",
104}; 108};
105 109
106struct opstack_op { 110struct opstack_op {
@@ -139,6 +143,7 @@ struct pred_stack {
139 int index; 143 int index;
140}; 144};
141 145
146/* If not of not match is equal to not of not, then it is a match */
142#define DEFINE_COMPARISON_PRED(type) \ 147#define DEFINE_COMPARISON_PRED(type) \
143static int filter_pred_##type(struct filter_pred *pred, void *event) \ 148static int filter_pred_##type(struct filter_pred *pred, void *event) \
144{ \ 149{ \
@@ -166,7 +171,7 @@ static int filter_pred_##type(struct filter_pred *pred, void *event) \
166 break; \ 171 break; \
167 } \ 172 } \
168 \ 173 \
169 return match; \ 174 return !!match == !pred->not; \
170} 175}
171 176
172#define DEFINE_EQUALITY_PRED(size) \ 177#define DEFINE_EQUALITY_PRED(size) \
@@ -1028,7 +1033,7 @@ static int init_pred(struct filter_parse_state *ps,
1028 } 1033 }
1029 1034
1030 if (pred->op == OP_NE) 1035 if (pred->op == OP_NE)
1031 pred->not = 1; 1036 pred->not ^= 1;
1032 1037
1033 pred->fn = fn; 1038 pred->fn = fn;
1034 return 0; 1039 return 0;
@@ -1590,6 +1595,17 @@ static int replace_preds(struct ftrace_event_call *call,
1590 continue; 1595 continue;
1591 } 1596 }
1592 1597
1598 if (elt->op == OP_NOT) {
1599 if (!n_preds || operand1 || operand2) {
1600 parse_error(ps, FILT_ERR_ILLEGAL_NOT_OP, 0);
1601 err = -EINVAL;
1602 goto fail;
1603 }
1604 if (!dry_run)
1605 filter->preds[n_preds - 1].not ^= 1;
1606 continue;
1607 }
1608
1593 if (WARN_ON(n_preds++ == MAX_FILTER_PRED)) { 1609 if (WARN_ON(n_preds++ == MAX_FILTER_PRED)) {
1594 parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); 1610 parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0);
1595 err = -ENOSPC; 1611 err = -ENOSPC;