diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace.h | 66 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 86 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 1020 |
3 files changed, 883 insertions, 289 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 866d0108fd2f..7736fe8c1b76 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -735,6 +735,7 @@ struct ftrace_event_field { | |||
735 | struct event_filter { | 735 | struct event_filter { |
736 | int n_preds; | 736 | int n_preds; |
737 | struct filter_pred **preds; | 737 | struct filter_pred **preds; |
738 | char *filter_string; | ||
738 | }; | 739 | }; |
739 | 740 | ||
740 | struct event_subsystem { | 741 | struct event_subsystem { |
@@ -746,7 +747,8 @@ struct event_subsystem { | |||
746 | 747 | ||
747 | struct filter_pred; | 748 | struct filter_pred; |
748 | 749 | ||
749 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event); | 750 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, |
751 | int val1, int val2); | ||
750 | 752 | ||
751 | struct filter_pred { | 753 | struct filter_pred { |
752 | filter_pred_fn_t fn; | 754 | filter_pred_fn_t fn; |
@@ -756,23 +758,18 @@ struct filter_pred { | |||
756 | char *field_name; | 758 | char *field_name; |
757 | int offset; | 759 | int offset; |
758 | int not; | 760 | int not; |
759 | int or; | 761 | int op; |
760 | int compound; | 762 | int pop_n; |
761 | int clear; | ||
762 | }; | 763 | }; |
763 | 764 | ||
764 | extern void filter_free_pred(struct filter_pred *pred); | 765 | extern void print_event_filter(struct ftrace_event_call *call, |
765 | extern void filter_print_preds(struct ftrace_event_call *call, | ||
766 | struct trace_seq *s); | 766 | struct trace_seq *s); |
767 | extern int filter_parse(char **pbuf, struct filter_pred *pred); | 767 | extern int apply_event_filter(struct ftrace_event_call *call, |
768 | extern int filter_add_pred(struct ftrace_event_call *call, | 768 | char *filter_string); |
769 | struct filter_pred *pred); | 769 | extern int apply_subsystem_event_filter(struct event_subsystem *system, |
770 | extern void filter_disable_preds(struct ftrace_event_call *call); | 770 | char *filter_string); |
771 | extern void filter_free_subsystem_preds(struct event_subsystem *system); | 771 | extern void print_subsystem_event_filter(struct event_subsystem *system, |
772 | extern void filter_print_subsystem_preds(struct event_subsystem *system, | ||
773 | struct trace_seq *s); | 772 | struct trace_seq *s); |
774 | extern int filter_add_subsystem_pred(struct event_subsystem *system, | ||
775 | struct filter_pred *pred); | ||
776 | 773 | ||
777 | static inline int | 774 | static inline int |
778 | filter_check_discard(struct ftrace_event_call *call, void *rec, | 775 | filter_check_discard(struct ftrace_event_call *call, void *rec, |
@@ -787,6 +784,47 @@ filter_check_discard(struct ftrace_event_call *call, void *rec, | |||
787 | return 0; | 784 | return 0; |
788 | } | 785 | } |
789 | 786 | ||
787 | #define DEFINE_COMPARISON_PRED(type) \ | ||
788 | static int filter_pred_##type(struct filter_pred *pred, void *event, \ | ||
789 | int val1, int val2) \ | ||
790 | { \ | ||
791 | type *addr = (type *)(event + pred->offset); \ | ||
792 | type val = (type)pred->val; \ | ||
793 | int match = 0; \ | ||
794 | \ | ||
795 | switch (pred->op) { \ | ||
796 | case OP_LT: \ | ||
797 | match = (*addr < val); \ | ||
798 | break; \ | ||
799 | case OP_LE: \ | ||
800 | match = (*addr <= val); \ | ||
801 | break; \ | ||
802 | case OP_GT: \ | ||
803 | match = (*addr > val); \ | ||
804 | break; \ | ||
805 | case OP_GE: \ | ||
806 | match = (*addr >= val); \ | ||
807 | break; \ | ||
808 | default: \ | ||
809 | break; \ | ||
810 | } \ | ||
811 | \ | ||
812 | return match; \ | ||
813 | } | ||
814 | |||
815 | #define DEFINE_EQUALITY_PRED(size) \ | ||
816 | static int filter_pred_##size(struct filter_pred *pred, void *event, \ | ||
817 | int val1, int val2) \ | ||
818 | { \ | ||
819 | u##size *addr = (u##size *)(event + pred->offset); \ | ||
820 | u##size val = (u##size)pred->val; \ | ||
821 | int match; \ | ||
822 | \ | ||
823 | match = (val == *addr) ^ pred->not; \ | ||
824 | \ | ||
825 | return match; \ | ||
826 | } | ||
827 | |||
790 | extern struct list_head ftrace_events; | 828 | extern struct list_head ftrace_events; |
791 | 829 | ||
792 | extern const char *__start___trace_bprintk_fmt[]; | 830 | extern const char *__start___trace_bprintk_fmt[]; |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index bbbea7479371..f789ca540fe1 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -492,7 +492,7 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
492 | 492 | ||
493 | trace_seq_init(s); | 493 | trace_seq_init(s); |
494 | 494 | ||
495 | filter_print_preds(call, s); | 495 | print_event_filter(call, s); |
496 | r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); | 496 | r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); |
497 | 497 | ||
498 | kfree(s); | 498 | kfree(s); |
@@ -505,40 +505,26 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
505 | loff_t *ppos) | 505 | loff_t *ppos) |
506 | { | 506 | { |
507 | struct ftrace_event_call *call = filp->private_data; | 507 | struct ftrace_event_call *call = filp->private_data; |
508 | char buf[64], *pbuf = buf; | 508 | char *buf; |
509 | struct filter_pred *pred; | ||
510 | int err; | 509 | int err; |
511 | 510 | ||
512 | if (cnt >= sizeof(buf)) | 511 | if (cnt >= PAGE_SIZE) |
513 | return -EINVAL; | 512 | return -EINVAL; |
514 | 513 | ||
515 | if (copy_from_user(&buf, ubuf, cnt)) | 514 | buf = (char *)__get_free_page(GFP_TEMPORARY); |
516 | return -EFAULT; | 515 | if (!buf) |
517 | buf[cnt] = '\0'; | ||
518 | |||
519 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); | ||
520 | if (!pred) | ||
521 | return -ENOMEM; | 516 | return -ENOMEM; |
522 | 517 | ||
523 | err = filter_parse(&pbuf, pred); | 518 | if (copy_from_user(buf, ubuf, cnt)) { |
524 | if (err < 0) { | 519 | free_page((unsigned long) buf); |
525 | filter_free_pred(pred); | 520 | return -EFAULT; |
526 | return err; | ||
527 | } | ||
528 | |||
529 | if (pred->clear) { | ||
530 | filter_disable_preds(call); | ||
531 | filter_free_pred(pred); | ||
532 | return cnt; | ||
533 | } | 521 | } |
522 | buf[cnt] = '\0'; | ||
534 | 523 | ||
535 | err = filter_add_pred(call, pred); | 524 | err = apply_event_filter(call, buf); |
536 | if (err < 0) { | 525 | free_page((unsigned long) buf); |
537 | filter_free_pred(pred); | 526 | if (err < 0) |
538 | return err; | 527 | return err; |
539 | } | ||
540 | |||
541 | filter_free_pred(pred); | ||
542 | 528 | ||
543 | *ppos += cnt; | 529 | *ppos += cnt; |
544 | 530 | ||
@@ -562,7 +548,7 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
562 | 548 | ||
563 | trace_seq_init(s); | 549 | trace_seq_init(s); |
564 | 550 | ||
565 | filter_print_subsystem_preds(system, s); | 551 | print_subsystem_event_filter(system, s); |
566 | r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); | 552 | r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len); |
567 | 553 | ||
568 | kfree(s); | 554 | kfree(s); |
@@ -575,38 +561,26 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
575 | loff_t *ppos) | 561 | loff_t *ppos) |
576 | { | 562 | { |
577 | struct event_subsystem *system = filp->private_data; | 563 | struct event_subsystem *system = filp->private_data; |
578 | char buf[64], *pbuf = buf; | 564 | char *buf; |
579 | struct filter_pred *pred; | ||
580 | int err; | 565 | int err; |
581 | 566 | ||
582 | if (cnt >= sizeof(buf)) | 567 | if (cnt >= PAGE_SIZE) |
583 | return -EINVAL; | 568 | return -EINVAL; |
584 | 569 | ||
585 | if (copy_from_user(&buf, ubuf, cnt)) | 570 | buf = (char *)__get_free_page(GFP_TEMPORARY); |
586 | return -EFAULT; | 571 | if (!buf) |
587 | buf[cnt] = '\0'; | ||
588 | |||
589 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); | ||
590 | if (!pred) | ||
591 | return -ENOMEM; | 572 | return -ENOMEM; |
592 | 573 | ||
593 | err = filter_parse(&pbuf, pred); | 574 | if (copy_from_user(buf, ubuf, cnt)) { |
594 | if (err < 0) { | 575 | free_page((unsigned long) buf); |
595 | filter_free_pred(pred); | 576 | return -EFAULT; |
596 | return err; | ||
597 | } | ||
598 | |||
599 | if (pred->clear) { | ||
600 | filter_free_subsystem_preds(system); | ||
601 | filter_free_pred(pred); | ||
602 | return cnt; | ||
603 | } | 577 | } |
578 | buf[cnt] = '\0'; | ||
604 | 579 | ||
605 | err = filter_add_subsystem_pred(system, pred); | 580 | err = apply_subsystem_event_filter(system, buf); |
606 | if (err < 0) { | 581 | free_page((unsigned long) buf); |
607 | filter_free_pred(pred); | 582 | if (err < 0) |
608 | return err; | 583 | return err; |
609 | } | ||
610 | 584 | ||
611 | *ppos += cnt; | 585 | *ppos += cnt; |
612 | 586 | ||
@@ -760,11 +734,21 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
760 | 734 | ||
761 | system->filter = NULL; | 735 | system->filter = NULL; |
762 | 736 | ||
737 | system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL); | ||
738 | if (!system->filter) { | ||
739 | pr_warning("Could not allocate filter for subsystem " | ||
740 | "'%s'\n", name); | ||
741 | return system->entry; | ||
742 | } | ||
743 | |||
763 | entry = debugfs_create_file("filter", 0644, system->entry, system, | 744 | entry = debugfs_create_file("filter", 0644, system->entry, system, |
764 | &ftrace_subsystem_filter_fops); | 745 | &ftrace_subsystem_filter_fops); |
765 | if (!entry) | 746 | if (!entry) { |
747 | kfree(system->filter); | ||
748 | system->filter = NULL; | ||
766 | pr_warning("Could not create debugfs " | 749 | pr_warning("Could not create debugfs " |
767 | "'%s/filter' entry\n", name); | 750 | "'%s/filter' entry\n", name); |
751 | } | ||
768 | 752 | ||
769 | return system->entry; | 753 | return system->entry; |
770 | } | 754 | } |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 1e861eca3d02..f49486687ee2 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -29,51 +29,130 @@ | |||
29 | 29 | ||
30 | static DEFINE_MUTEX(filter_mutex); | 30 | static DEFINE_MUTEX(filter_mutex); |
31 | 31 | ||
32 | static int filter_pred_64(struct filter_pred *pred, void *event) | 32 | enum filter_op_ids |
33 | { | 33 | { |
34 | u64 *addr = (u64 *)(event + pred->offset); | 34 | OP_OR, |
35 | u64 val = (u64)pred->val; | 35 | OP_AND, |
36 | int match; | 36 | OP_NE, |
37 | 37 | OP_EQ, | |
38 | match = (val == *addr) ^ pred->not; | 38 | OP_LT, |
39 | 39 | OP_LE, | |
40 | return match; | 40 | OP_GT, |
41 | } | 41 | OP_GE, |
42 | 42 | OP_NONE, | |
43 | static int filter_pred_32(struct filter_pred *pred, void *event) | 43 | OP_OPEN_PAREN, |
44 | { | 44 | }; |
45 | u32 *addr = (u32 *)(event + pred->offset); | 45 | |
46 | u32 val = (u32)pred->val; | 46 | struct filter_op { |
47 | int match; | 47 | int id; |
48 | 48 | char *string; | |
49 | match = (val == *addr) ^ pred->not; | 49 | int precedence; |
50 | 50 | }; | |
51 | return match; | 51 | |
52 | } | 52 | static struct filter_op filter_ops[] = { |
53 | 53 | { OP_OR, "||", 1 }, | |
54 | static int filter_pred_16(struct filter_pred *pred, void *event) | 54 | { OP_AND, "&&", 2 }, |
55 | { OP_NE, "!=", 4 }, | ||
56 | { OP_EQ, "==", 4 }, | ||
57 | { OP_LT, "<", 5 }, | ||
58 | { OP_LE, "<=", 5 }, | ||
59 | { OP_GT, ">", 5 }, | ||
60 | { OP_GE, ">=", 5 }, | ||
61 | { OP_NONE, "OP_NONE", 0 }, | ||
62 | { OP_OPEN_PAREN, "(", 0 }, | ||
63 | }; | ||
64 | |||
65 | enum { | ||
66 | FILT_ERR_NONE, | ||
67 | FILT_ERR_INVALID_OP, | ||
68 | FILT_ERR_UNBALANCED_PAREN, | ||
69 | FILT_ERR_TOO_MANY_OPERANDS, | ||
70 | FILT_ERR_OPERAND_TOO_LONG, | ||
71 | FILT_ERR_FIELD_NOT_FOUND, | ||
72 | FILT_ERR_ILLEGAL_FIELD_OP, | ||
73 | FILT_ERR_ILLEGAL_INTVAL, | ||
74 | FILT_ERR_BAD_SUBSYS_FILTER, | ||
75 | FILT_ERR_TOO_MANY_PREDS, | ||
76 | FILT_ERR_MISSING_FIELD, | ||
77 | FILT_ERR_INVALID_FILTER, | ||
78 | }; | ||
79 | |||
80 | static char *err_text[] = { | ||
81 | "No error", | ||
82 | "Invalid operator", | ||
83 | "Unbalanced parens", | ||
84 | "Too many operands", | ||
85 | "Operand too long", | ||
86 | "Field not found", | ||
87 | "Illegal operation for field type", | ||
88 | "Illegal integer value", | ||
89 | "Couldn't find or set field in one of a subsystem's events", | ||
90 | "Too many terms in predicate expression", | ||
91 | "Missing field name and/or value", | ||
92 | "Meaningless filter expression", | ||
93 | }; | ||
94 | |||
95 | struct opstack_op { | ||
96 | int op; | ||
97 | struct list_head list; | ||
98 | }; | ||
99 | |||
100 | struct postfix_elt { | ||
101 | int op; | ||
102 | char *operand; | ||
103 | struct list_head list; | ||
104 | }; | ||
105 | |||
106 | struct filter_parse_state { | ||
107 | struct filter_op *ops; | ||
108 | struct list_head opstack; | ||
109 | struct list_head postfix; | ||
110 | int lasterr; | ||
111 | int lasterr_pos; | ||
112 | |||
113 | struct { | ||
114 | char *string; | ||
115 | unsigned int cnt; | ||
116 | unsigned int tail; | ||
117 | } infix; | ||
118 | |||
119 | struct { | ||
120 | char string[MAX_FILTER_STR_VAL]; | ||
121 | int pos; | ||
122 | unsigned int tail; | ||
123 | } operand; | ||
124 | }; | ||
125 | |||
126 | DEFINE_COMPARISON_PRED(s64); | ||
127 | DEFINE_COMPARISON_PRED(u64); | ||
128 | DEFINE_COMPARISON_PRED(s32); | ||
129 | DEFINE_COMPARISON_PRED(u32); | ||
130 | DEFINE_COMPARISON_PRED(s16); | ||
131 | DEFINE_COMPARISON_PRED(u16); | ||
132 | DEFINE_COMPARISON_PRED(s8); | ||
133 | DEFINE_COMPARISON_PRED(u8); | ||
134 | |||
135 | DEFINE_EQUALITY_PRED(64); | ||
136 | DEFINE_EQUALITY_PRED(32); | ||
137 | DEFINE_EQUALITY_PRED(16); | ||
138 | DEFINE_EQUALITY_PRED(8); | ||
139 | |||
140 | static int filter_pred_and(struct filter_pred *pred __attribute((unused)), | ||
141 | void *event __attribute((unused)), | ||
142 | int val1, int val2) | ||
55 | { | 143 | { |
56 | u16 *addr = (u16 *)(event + pred->offset); | 144 | return val1 && val2; |
57 | u16 val = (u16)pred->val; | ||
58 | int match; | ||
59 | |||
60 | match = (val == *addr) ^ pred->not; | ||
61 | |||
62 | return match; | ||
63 | } | 145 | } |
64 | 146 | ||
65 | static int filter_pred_8(struct filter_pred *pred, void *event) | 147 | static int filter_pred_or(struct filter_pred *pred __attribute((unused)), |
148 | void *event __attribute((unused)), | ||
149 | int val1, int val2) | ||
66 | { | 150 | { |
67 | u8 *addr = (u8 *)(event + pred->offset); | 151 | return val1 || val2; |
68 | u8 val = (u8)pred->val; | ||
69 | int match; | ||
70 | |||
71 | match = (val == *addr) ^ pred->not; | ||
72 | |||
73 | return match; | ||
74 | } | 152 | } |
75 | 153 | ||
76 | static int filter_pred_string(struct filter_pred *pred, void *event) | 154 | static int filter_pred_string(struct filter_pred *pred, void *event, |
155 | int val1, int val2) | ||
77 | { | 156 | { |
78 | char *addr = (char *)(event + pred->offset); | 157 | char *addr = (char *)(event + pred->offset); |
79 | int cmp, match; | 158 | int cmp, match; |
@@ -85,7 +164,8 @@ static int filter_pred_string(struct filter_pred *pred, void *event) | |||
85 | return match; | 164 | return match; |
86 | } | 165 | } |
87 | 166 | ||
88 | static int filter_pred_none(struct filter_pred *pred, void *event) | 167 | static int filter_pred_none(struct filter_pred *pred, void *event, |
168 | int val1, int val2) | ||
89 | { | 169 | { |
90 | return 0; | 170 | return 0; |
91 | } | 171 | } |
@@ -94,66 +174,119 @@ static int filter_pred_none(struct filter_pred *pred, void *event) | |||
94 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 174 | int filter_match_preds(struct ftrace_event_call *call, void *rec) |
95 | { | 175 | { |
96 | struct event_filter *filter = call->filter; | 176 | struct event_filter *filter = call->filter; |
97 | int i, matched, and_failed = 0; | 177 | int match, top = 0, val1 = 0, val2 = 0; |
178 | int stack[MAX_FILTER_PRED]; | ||
98 | struct filter_pred *pred; | 179 | struct filter_pred *pred; |
180 | int i; | ||
99 | 181 | ||
100 | for (i = 0; i < filter->n_preds; i++) { | 182 | for (i = 0; i < filter->n_preds; i++) { |
101 | pred = filter->preds[i]; | 183 | pred = filter->preds[i]; |
102 | if (and_failed && !pred->or) | 184 | if (!pred->pop_n) { |
185 | match = pred->fn(pred, rec, val1, val2); | ||
186 | stack[top++] = match; | ||
103 | continue; | 187 | continue; |
104 | matched = pred->fn(pred, rec); | 188 | } |
105 | if (!matched && !pred->or) { | 189 | if (pred->pop_n > top) { |
106 | and_failed = 1; | 190 | WARN_ON_ONCE(1); |
107 | continue; | 191 | return 0; |
108 | } else if (matched && pred->or) | 192 | } |
109 | return 1; | 193 | val1 = stack[--top]; |
194 | val2 = stack[--top]; | ||
195 | match = pred->fn(pred, rec, val1, val2); | ||
196 | stack[top++] = match; | ||
110 | } | 197 | } |
111 | 198 | ||
112 | if (and_failed) | 199 | return stack[--top]; |
113 | return 0; | ||
114 | |||
115 | return 1; | ||
116 | } | 200 | } |
117 | EXPORT_SYMBOL_GPL(filter_match_preds); | 201 | EXPORT_SYMBOL_GPL(filter_match_preds); |
118 | 202 | ||
119 | static void __filter_print_preds(struct event_filter *filter, | 203 | static void parse_error(struct filter_parse_state *ps, int err, int pos) |
120 | struct trace_seq *s) | ||
121 | { | 204 | { |
122 | struct filter_pred *pred; | 205 | ps->lasterr = err; |
123 | char *field_name; | 206 | ps->lasterr_pos = pos; |
124 | int i; | 207 | } |
125 | 208 | ||
126 | if (!filter || !filter->n_preds) { | 209 | static void remove_filter_string(struct event_filter *filter) |
127 | trace_seq_printf(s, "none\n"); | 210 | { |
211 | kfree(filter->filter_string); | ||
212 | filter->filter_string = NULL; | ||
213 | } | ||
214 | |||
215 | static int replace_filter_string(struct event_filter *filter, | ||
216 | char *filter_string) | ||
217 | { | ||
218 | kfree(filter->filter_string); | ||
219 | filter->filter_string = kstrdup(filter_string, GFP_KERNEL); | ||
220 | if (!filter->filter_string) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int append_filter_string(struct event_filter *filter, | ||
227 | char *string) | ||
228 | { | ||
229 | int newlen; | ||
230 | char *new_filter_string; | ||
231 | |||
232 | BUG_ON(!filter->filter_string); | ||
233 | newlen = strlen(filter->filter_string) + strlen(string) + 1; | ||
234 | new_filter_string = kmalloc(newlen, GFP_KERNEL); | ||
235 | if (!new_filter_string) | ||
236 | return -ENOMEM; | ||
237 | |||
238 | strcpy(new_filter_string, filter->filter_string); | ||
239 | strcat(new_filter_string, string); | ||
240 | kfree(filter->filter_string); | ||
241 | filter->filter_string = new_filter_string; | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static void append_filter_err(struct filter_parse_state *ps, | ||
247 | struct event_filter *filter) | ||
248 | { | ||
249 | int pos = ps->lasterr_pos; | ||
250 | char *buf, *pbuf; | ||
251 | |||
252 | buf = (char *)__get_free_page(GFP_TEMPORARY); | ||
253 | if (!buf) | ||
128 | return; | 254 | return; |
129 | } | ||
130 | 255 | ||
131 | for (i = 0; i < filter->n_preds; i++) { | 256 | append_filter_string(filter, "\n"); |
132 | pred = filter->preds[i]; | 257 | memset(buf, ' ', PAGE_SIZE); |
133 | field_name = pred->field_name; | 258 | if (pos > PAGE_SIZE - 128) |
134 | if (i) | 259 | pos = 0; |
135 | trace_seq_printf(s, pred->or ? "|| " : "&& "); | 260 | buf[pos] = '^'; |
136 | trace_seq_printf(s, "%s ", field_name); | 261 | pbuf = &buf[pos] + 1; |
137 | trace_seq_printf(s, pred->not ? "!= " : "== "); | 262 | |
138 | if (pred->str_len) | 263 | sprintf(pbuf, "\nparse_error: %s\n", err_text[ps->lasterr]); |
139 | trace_seq_printf(s, "%s\n", pred->str_val); | 264 | append_filter_string(filter, buf); |
140 | else | 265 | free_page((unsigned long) buf); |
141 | trace_seq_printf(s, "%llu\n", pred->val); | ||
142 | } | ||
143 | } | 266 | } |
144 | 267 | ||
145 | void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s) | 268 | void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) |
146 | { | 269 | { |
270 | struct event_filter *filter = call->filter; | ||
271 | |||
147 | mutex_lock(&filter_mutex); | 272 | mutex_lock(&filter_mutex); |
148 | __filter_print_preds(call->filter, s); | 273 | if (filter->filter_string) |
274 | trace_seq_printf(s, "%s\n", filter->filter_string); | ||
275 | else | ||
276 | trace_seq_printf(s, "none\n"); | ||
149 | mutex_unlock(&filter_mutex); | 277 | mutex_unlock(&filter_mutex); |
150 | } | 278 | } |
151 | 279 | ||
152 | void filter_print_subsystem_preds(struct event_subsystem *system, | 280 | void print_subsystem_event_filter(struct event_subsystem *system, |
153 | struct trace_seq *s) | 281 | struct trace_seq *s) |
154 | { | 282 | { |
283 | struct event_filter *filter = system->filter; | ||
284 | |||
155 | mutex_lock(&filter_mutex); | 285 | mutex_lock(&filter_mutex); |
156 | __filter_print_preds(system->filter, s); | 286 | if (filter->filter_string) |
287 | trace_seq_printf(s, "%s\n", filter->filter_string); | ||
288 | else | ||
289 | trace_seq_printf(s, "none\n"); | ||
157 | mutex_unlock(&filter_mutex); | 290 | mutex_unlock(&filter_mutex); |
158 | } | 291 | } |
159 | 292 | ||
@@ -170,7 +303,7 @@ find_event_field(struct ftrace_event_call *call, char *name) | |||
170 | return NULL; | 303 | return NULL; |
171 | } | 304 | } |
172 | 305 | ||
173 | void filter_free_pred(struct filter_pred *pred) | 306 | static void filter_free_pred(struct filter_pred *pred) |
174 | { | 307 | { |
175 | if (!pred) | 308 | if (!pred) |
176 | return; | 309 | return; |
@@ -191,15 +324,17 @@ static int filter_set_pred(struct filter_pred *dest, | |||
191 | filter_pred_fn_t fn) | 324 | filter_pred_fn_t fn) |
192 | { | 325 | { |
193 | *dest = *src; | 326 | *dest = *src; |
194 | dest->field_name = kstrdup(src->field_name, GFP_KERNEL); | 327 | if (src->field_name) { |
195 | if (!dest->field_name) | 328 | dest->field_name = kstrdup(src->field_name, GFP_KERNEL); |
196 | return -ENOMEM; | 329 | if (!dest->field_name) |
330 | return -ENOMEM; | ||
331 | } | ||
197 | dest->fn = fn; | 332 | dest->fn = fn; |
198 | 333 | ||
199 | return 0; | 334 | return 0; |
200 | } | 335 | } |
201 | 336 | ||
202 | static void __filter_disable_preds(struct ftrace_event_call *call) | 337 | static void filter_disable_preds(struct ftrace_event_call *call) |
203 | { | 338 | { |
204 | struct event_filter *filter = call->filter; | 339 | struct event_filter *filter = call->filter; |
205 | int i; | 340 | int i; |
@@ -211,13 +346,6 @@ static void __filter_disable_preds(struct ftrace_event_call *call) | |||
211 | filter->preds[i]->fn = filter_pred_none; | 346 | filter->preds[i]->fn = filter_pred_none; |
212 | } | 347 | } |
213 | 348 | ||
214 | void filter_disable_preds(struct ftrace_event_call *call) | ||
215 | { | ||
216 | mutex_lock(&filter_mutex); | ||
217 | __filter_disable_preds(call); | ||
218 | mutex_unlock(&filter_mutex); | ||
219 | } | ||
220 | |||
221 | int init_preds(struct ftrace_event_call *call) | 349 | int init_preds(struct ftrace_event_call *call) |
222 | { | 350 | { |
223 | struct event_filter *filter; | 351 | struct event_filter *filter; |
@@ -258,48 +386,43 @@ oom: | |||
258 | } | 386 | } |
259 | EXPORT_SYMBOL_GPL(init_preds); | 387 | EXPORT_SYMBOL_GPL(init_preds); |
260 | 388 | ||
261 | static void __filter_free_subsystem_preds(struct event_subsystem *system) | 389 | static void filter_free_subsystem_preds(struct event_subsystem *system) |
262 | { | 390 | { |
263 | struct event_filter *filter = system->filter; | 391 | struct event_filter *filter = system->filter; |
264 | struct ftrace_event_call *call; | 392 | struct ftrace_event_call *call; |
265 | int i; | 393 | int i; |
266 | 394 | ||
267 | if (filter && filter->n_preds) { | 395 | if (filter->n_preds) { |
268 | for (i = 0; i < filter->n_preds; i++) | 396 | for (i = 0; i < filter->n_preds; i++) |
269 | filter_free_pred(filter->preds[i]); | 397 | filter_free_pred(filter->preds[i]); |
270 | kfree(filter->preds); | 398 | kfree(filter->preds); |
271 | kfree(filter); | 399 | filter->preds = NULL; |
272 | system->filter = NULL; | 400 | filter->n_preds = 0; |
273 | } | 401 | } |
274 | 402 | ||
275 | list_for_each_entry(call, &ftrace_events, list) { | 403 | list_for_each_entry(call, &ftrace_events, list) { |
276 | if (!call->define_fields) | 404 | if (!call->define_fields) |
277 | continue; | 405 | continue; |
278 | 406 | ||
279 | if (!strcmp(call->system, system->name)) | 407 | if (!strcmp(call->system, system->name)) { |
280 | __filter_disable_preds(call); | 408 | filter_disable_preds(call); |
409 | remove_filter_string(call->filter); | ||
410 | } | ||
281 | } | 411 | } |
282 | } | 412 | } |
283 | 413 | ||
284 | void filter_free_subsystem_preds(struct event_subsystem *system) | 414 | static int filter_add_pred_fn(struct filter_parse_state *ps, |
285 | { | 415 | struct ftrace_event_call *call, |
286 | mutex_lock(&filter_mutex); | ||
287 | __filter_free_subsystem_preds(system); | ||
288 | mutex_unlock(&filter_mutex); | ||
289 | } | ||
290 | |||
291 | static int filter_add_pred_fn(struct ftrace_event_call *call, | ||
292 | struct filter_pred *pred, | 416 | struct filter_pred *pred, |
293 | filter_pred_fn_t fn) | 417 | filter_pred_fn_t fn) |
294 | { | 418 | { |
295 | struct event_filter *filter = call->filter; | 419 | struct event_filter *filter = call->filter; |
296 | int idx, err; | 420 | int idx, err; |
297 | 421 | ||
298 | if (filter->n_preds && !pred->compound) | 422 | if (filter->n_preds == MAX_FILTER_PRED) { |
299 | __filter_disable_preds(call); | 423 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); |
300 | |||
301 | if (filter->n_preds == MAX_FILTER_PRED) | ||
302 | return -ENOSPC; | 424 | return -ENOSPC; |
425 | } | ||
303 | 426 | ||
304 | idx = filter->n_preds; | 427 | idx = filter->n_preds; |
305 | filter_clear_pred(filter->preds[idx]); | 428 | filter_clear_pred(filter->preds[idx]); |
@@ -321,94 +444,132 @@ static int is_string_field(const char *type) | |||
321 | return 0; | 444 | return 0; |
322 | } | 445 | } |
323 | 446 | ||
324 | static int __filter_add_pred(struct ftrace_event_call *call, | 447 | static int is_legal_op(struct ftrace_event_field *field, int op) |
325 | struct filter_pred *pred) | 448 | { |
449 | if (is_string_field(field->type) && (op != OP_EQ && op != OP_NE)) | ||
450 | return 0; | ||
451 | |||
452 | return 1; | ||
453 | } | ||
454 | |||
455 | static filter_pred_fn_t select_comparison_fn(int op, int field_size, | ||
456 | int field_is_signed) | ||
457 | { | ||
458 | filter_pred_fn_t fn = NULL; | ||
459 | |||
460 | switch (field_size) { | ||
461 | case 8: | ||
462 | if (op == OP_EQ || op == OP_NE) | ||
463 | fn = filter_pred_64; | ||
464 | else if (field_is_signed) | ||
465 | fn = filter_pred_s64; | ||
466 | else | ||
467 | fn = filter_pred_u64; | ||
468 | break; | ||
469 | case 4: | ||
470 | if (op == OP_EQ || op == OP_NE) | ||
471 | fn = filter_pred_32; | ||
472 | else if (field_is_signed) | ||
473 | fn = filter_pred_s32; | ||
474 | else | ||
475 | fn = filter_pred_u32; | ||
476 | break; | ||
477 | case 2: | ||
478 | if (op == OP_EQ || op == OP_NE) | ||
479 | fn = filter_pred_16; | ||
480 | else if (field_is_signed) | ||
481 | fn = filter_pred_s16; | ||
482 | else | ||
483 | fn = filter_pred_u16; | ||
484 | break; | ||
485 | case 1: | ||
486 | if (op == OP_EQ || op == OP_NE) | ||
487 | fn = filter_pred_8; | ||
488 | else if (field_is_signed) | ||
489 | fn = filter_pred_s8; | ||
490 | else | ||
491 | fn = filter_pred_u8; | ||
492 | break; | ||
493 | } | ||
494 | |||
495 | return fn; | ||
496 | } | ||
497 | |||
498 | static int filter_add_pred(struct filter_parse_state *ps, | ||
499 | struct ftrace_event_call *call, | ||
500 | struct filter_pred *pred) | ||
326 | { | 501 | { |
327 | struct ftrace_event_field *field; | 502 | struct ftrace_event_field *field; |
328 | filter_pred_fn_t fn; | 503 | filter_pred_fn_t fn; |
329 | unsigned long long val; | 504 | unsigned long long val; |
330 | 505 | ||
506 | pred->fn = filter_pred_none; | ||
507 | |||
508 | if (pred->op == OP_AND) { | ||
509 | pred->pop_n = 2; | ||
510 | return filter_add_pred_fn(ps, call, pred, filter_pred_and); | ||
511 | } else if (pred->op == OP_OR) { | ||
512 | pred->pop_n = 2; | ||
513 | return filter_add_pred_fn(ps, call, pred, filter_pred_or); | ||
514 | } | ||
515 | |||
331 | field = find_event_field(call, pred->field_name); | 516 | field = find_event_field(call, pred->field_name); |
332 | if (!field) | 517 | if (!field) { |
518 | parse_error(ps, FILT_ERR_FIELD_NOT_FOUND, 0); | ||
333 | return -EINVAL; | 519 | return -EINVAL; |
520 | } | ||
334 | 521 | ||
335 | pred->fn = filter_pred_none; | ||
336 | pred->offset = field->offset; | 522 | pred->offset = field->offset; |
337 | 523 | ||
524 | if (!is_legal_op(field, pred->op)) { | ||
525 | parse_error(ps, FILT_ERR_ILLEGAL_FIELD_OP, 0); | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
338 | if (is_string_field(field->type)) { | 529 | if (is_string_field(field->type)) { |
339 | fn = filter_pred_string; | 530 | fn = filter_pred_string; |
340 | pred->str_len = field->size; | 531 | pred->str_len = field->size; |
341 | return filter_add_pred_fn(call, pred, fn); | 532 | if (pred->op == OP_NE) |
533 | pred->not = 1; | ||
534 | return filter_add_pred_fn(ps, call, pred, fn); | ||
342 | } else { | 535 | } else { |
343 | if (strict_strtoull(pred->str_val, 0, &val)) | 536 | if (strict_strtoull(pred->str_val, 0, &val)) { |
537 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); | ||
344 | return -EINVAL; | 538 | return -EINVAL; |
539 | } | ||
345 | pred->val = val; | 540 | pred->val = val; |
346 | } | 541 | } |
347 | 542 | ||
348 | switch (field->size) { | 543 | fn = select_comparison_fn(pred->op, field->size, field->is_signed); |
349 | case 8: | 544 | if (!fn) { |
350 | fn = filter_pred_64; | 545 | parse_error(ps, FILT_ERR_INVALID_OP, 0); |
351 | break; | ||
352 | case 4: | ||
353 | fn = filter_pred_32; | ||
354 | break; | ||
355 | case 2: | ||
356 | fn = filter_pred_16; | ||
357 | break; | ||
358 | case 1: | ||
359 | fn = filter_pred_8; | ||
360 | break; | ||
361 | default: | ||
362 | return -EINVAL; | 546 | return -EINVAL; |
363 | } | 547 | } |
364 | 548 | ||
365 | return filter_add_pred_fn(call, pred, fn); | 549 | if (pred->op == OP_NE) |
366 | } | 550 | pred->not = 1; |
367 | |||
368 | int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred) | ||
369 | { | ||
370 | int err; | ||
371 | |||
372 | mutex_lock(&filter_mutex); | ||
373 | err = __filter_add_pred(call, pred); | ||
374 | mutex_unlock(&filter_mutex); | ||
375 | 551 | ||
376 | return err; | 552 | return filter_add_pred_fn(ps, call, pred, fn); |
377 | } | 553 | } |
378 | 554 | ||
379 | int filter_add_subsystem_pred(struct event_subsystem *system, | 555 | static int filter_add_subsystem_pred(struct filter_parse_state *ps, |
380 | struct filter_pred *pred) | 556 | struct event_subsystem *system, |
557 | struct filter_pred *pred, | ||
558 | char *filter_string) | ||
381 | { | 559 | { |
382 | struct event_filter *filter = system->filter; | 560 | struct event_filter *filter = system->filter; |
383 | struct ftrace_event_call *call; | 561 | struct ftrace_event_call *call; |
384 | 562 | ||
385 | mutex_lock(&filter_mutex); | 563 | if (!filter->preds) { |
386 | |||
387 | if (filter && filter->n_preds && !pred->compound) { | ||
388 | __filter_free_subsystem_preds(system); | ||
389 | filter = NULL; | ||
390 | } | ||
391 | |||
392 | if (!filter) { | ||
393 | system->filter = kzalloc(sizeof(*filter), GFP_KERNEL); | ||
394 | if (!system->filter) { | ||
395 | mutex_unlock(&filter_mutex); | ||
396 | return -ENOMEM; | ||
397 | } | ||
398 | filter = system->filter; | ||
399 | filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), | 564 | filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), |
400 | GFP_KERNEL); | 565 | GFP_KERNEL); |
401 | 566 | ||
402 | if (!filter->preds) { | 567 | if (!filter->preds) |
403 | kfree(system->filter); | ||
404 | system->filter = NULL; | ||
405 | mutex_unlock(&filter_mutex); | ||
406 | return -ENOMEM; | 568 | return -ENOMEM; |
407 | } | ||
408 | } | 569 | } |
409 | 570 | ||
410 | if (filter->n_preds == MAX_FILTER_PRED) { | 571 | if (filter->n_preds == MAX_FILTER_PRED) { |
411 | mutex_unlock(&filter_mutex); | 572 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); |
412 | return -ENOSPC; | 573 | return -ENOSPC; |
413 | } | 574 | } |
414 | 575 | ||
@@ -424,97 +585,508 @@ int filter_add_subsystem_pred(struct event_subsystem *system, | |||
424 | if (strcmp(call->system, system->name)) | 585 | if (strcmp(call->system, system->name)) |
425 | continue; | 586 | continue; |
426 | 587 | ||
427 | err = __filter_add_pred(call, pred); | 588 | err = filter_add_pred(ps, call, pred); |
428 | if (err == -ENOMEM) { | 589 | if (err) { |
429 | filter->preds[filter->n_preds] = NULL; | 590 | filter_free_subsystem_preds(system); |
430 | filter->n_preds--; | 591 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); |
431 | mutex_unlock(&filter_mutex); | ||
432 | return err; | 592 | return err; |
433 | } | 593 | } |
594 | replace_filter_string(call->filter, filter_string); | ||
434 | } | 595 | } |
435 | 596 | ||
436 | mutex_unlock(&filter_mutex); | 597 | return 0; |
598 | } | ||
599 | |||
600 | static void parse_init(struct filter_parse_state *ps, | ||
601 | struct filter_op *ops, | ||
602 | char *infix_string) | ||
603 | { | ||
604 | memset(ps, '\0', sizeof(*ps)); | ||
605 | |||
606 | ps->infix.string = infix_string; | ||
607 | ps->infix.cnt = strlen(infix_string); | ||
608 | ps->ops = ops; | ||
609 | |||
610 | INIT_LIST_HEAD(&ps->opstack); | ||
611 | INIT_LIST_HEAD(&ps->postfix); | ||
612 | } | ||
613 | |||
614 | static char infix_next(struct filter_parse_state *ps) | ||
615 | { | ||
616 | ps->infix.cnt--; | ||
617 | |||
618 | return ps->infix.string[ps->infix.tail++]; | ||
619 | } | ||
620 | |||
621 | static char infix_peek(struct filter_parse_state *ps) | ||
622 | { | ||
623 | if (ps->infix.tail == strlen(ps->infix.string)) | ||
624 | return 0; | ||
625 | |||
626 | return ps->infix.string[ps->infix.tail]; | ||
627 | } | ||
628 | |||
629 | static void infix_advance(struct filter_parse_state *ps) | ||
630 | { | ||
631 | ps->infix.cnt--; | ||
632 | ps->infix.tail++; | ||
633 | } | ||
634 | |||
635 | static inline int is_precedence_lower(struct filter_parse_state *ps, | ||
636 | int a, int b) | ||
637 | { | ||
638 | return ps->ops[a].precedence < ps->ops[b].precedence; | ||
639 | } | ||
640 | |||
641 | static inline int is_op_char(struct filter_parse_state *ps, char c) | ||
642 | { | ||
643 | int i; | ||
644 | |||
645 | for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) { | ||
646 | if (ps->ops[i].string[0] == c) | ||
647 | return 1; | ||
648 | } | ||
437 | 649 | ||
438 | return 0; | 650 | return 0; |
439 | } | 651 | } |
440 | 652 | ||
441 | /* | 653 | static int infix_get_op(struct filter_parse_state *ps, char firstc) |
442 | * The filter format can be | 654 | { |
443 | * - 0, which means remove all filter preds | 655 | char nextc = infix_peek(ps); |
444 | * - [||/&&] <field> ==/!= <val> | 656 | char opstr[3]; |
445 | */ | 657 | int i; |
446 | int filter_parse(char **pbuf, struct filter_pred *pred) | 658 | |
447 | { | 659 | opstr[0] = firstc; |
448 | char *tok, *val_str = NULL; | 660 | opstr[1] = nextc; |
449 | int tok_n = 0; | 661 | opstr[2] = '\0'; |
450 | 662 | ||
451 | while ((tok = strsep(pbuf, " \n"))) { | 663 | for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) { |
452 | if (tok_n == 0) { | 664 | if (!strcmp(opstr, ps->ops[i].string)) { |
453 | if (!strcmp(tok, "0")) { | 665 | infix_advance(ps); |
454 | pred->clear = 1; | 666 | return ps->ops[i].id; |
455 | return 0; | ||
456 | } else if (!strcmp(tok, "&&")) { | ||
457 | pred->or = 0; | ||
458 | pred->compound = 1; | ||
459 | } else if (!strcmp(tok, "||")) { | ||
460 | pred->or = 1; | ||
461 | pred->compound = 1; | ||
462 | } else | ||
463 | pred->field_name = tok; | ||
464 | tok_n = 1; | ||
465 | continue; | ||
466 | } | 667 | } |
467 | if (tok_n == 1) { | 668 | } |
468 | if (!pred->field_name) | 669 | |
469 | pred->field_name = tok; | 670 | opstr[1] = '\0'; |
470 | else if (!strcmp(tok, "!=")) | 671 | |
471 | pred->not = 1; | 672 | for (i = 0; strcmp(ps->ops[i].string, "OP_NONE"); i++) { |
472 | else if (!strcmp(tok, "==")) | 673 | if (!strcmp(opstr, ps->ops[i].string)) |
473 | pred->not = 0; | 674 | return ps->ops[i].id; |
474 | else { | 675 | } |
475 | pred->field_name = NULL; | 676 | |
677 | return OP_NONE; | ||
678 | } | ||
679 | |||
680 | static inline void clear_operand_string(struct filter_parse_state *ps) | ||
681 | { | ||
682 | memset(ps->operand.string, '\0', MAX_FILTER_STR_VAL); | ||
683 | ps->operand.tail = 0; | ||
684 | } | ||
685 | |||
686 | static inline int append_operand_char(struct filter_parse_state *ps, char c) | ||
687 | { | ||
688 | if (ps->operand.tail == MAX_FILTER_STR_VAL) | ||
689 | return -EINVAL; | ||
690 | |||
691 | ps->operand.string[ps->operand.tail++] = c; | ||
692 | |||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | static int filter_opstack_push(struct filter_parse_state *ps, int op) | ||
697 | { | ||
698 | struct opstack_op *opstack_op; | ||
699 | |||
700 | opstack_op = kmalloc(sizeof(*opstack_op), GFP_KERNEL); | ||
701 | if (!opstack_op) | ||
702 | return -ENOMEM; | ||
703 | |||
704 | opstack_op->op = op; | ||
705 | list_add(&opstack_op->list, &ps->opstack); | ||
706 | |||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | static int filter_opstack_empty(struct filter_parse_state *ps) | ||
711 | { | ||
712 | return list_empty(&ps->opstack); | ||
713 | } | ||
714 | |||
715 | static int filter_opstack_top(struct filter_parse_state *ps) | ||
716 | { | ||
717 | struct opstack_op *opstack_op; | ||
718 | |||
719 | if (filter_opstack_empty(ps)) | ||
720 | return OP_NONE; | ||
721 | |||
722 | opstack_op = list_first_entry(&ps->opstack, struct opstack_op, list); | ||
723 | |||
724 | return opstack_op->op; | ||
725 | } | ||
726 | |||
727 | static int filter_opstack_pop(struct filter_parse_state *ps) | ||
728 | { | ||
729 | struct opstack_op *opstack_op; | ||
730 | int op; | ||
731 | |||
732 | if (filter_opstack_empty(ps)) | ||
733 | return OP_NONE; | ||
734 | |||
735 | opstack_op = list_first_entry(&ps->opstack, struct opstack_op, list); | ||
736 | op = opstack_op->op; | ||
737 | list_del(&opstack_op->list); | ||
738 | |||
739 | kfree(opstack_op); | ||
740 | |||
741 | return op; | ||
742 | } | ||
743 | |||
744 | static void filter_opstack_clear(struct filter_parse_state *ps) | ||
745 | { | ||
746 | while (!filter_opstack_empty(ps)) | ||
747 | filter_opstack_pop(ps); | ||
748 | } | ||
749 | |||
750 | static char *curr_operand(struct filter_parse_state *ps) | ||
751 | { | ||
752 | return ps->operand.string; | ||
753 | } | ||
754 | |||
755 | static int postfix_append_operand(struct filter_parse_state *ps, char *operand) | ||
756 | { | ||
757 | struct postfix_elt *elt; | ||
758 | |||
759 | elt = kmalloc(sizeof(*elt), GFP_KERNEL); | ||
760 | if (!elt) | ||
761 | return -ENOMEM; | ||
762 | |||
763 | elt->op = OP_NONE; | ||
764 | elt->operand = kstrdup(operand, GFP_KERNEL); | ||
765 | if (!elt->operand) { | ||
766 | kfree(elt); | ||
767 | return -ENOMEM; | ||
768 | } | ||
769 | |||
770 | list_add_tail(&elt->list, &ps->postfix); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static int postfix_append_op(struct filter_parse_state *ps, int op) | ||
776 | { | ||
777 | struct postfix_elt *elt; | ||
778 | |||
779 | elt = kmalloc(sizeof(*elt), GFP_KERNEL); | ||
780 | if (!elt) | ||
781 | return -ENOMEM; | ||
782 | |||
783 | elt->op = op; | ||
784 | elt->operand = NULL; | ||
785 | |||
786 | list_add_tail(&elt->list, &ps->postfix); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static void postfix_clear(struct filter_parse_state *ps) | ||
792 | { | ||
793 | struct postfix_elt *elt; | ||
794 | |||
795 | while (!list_empty(&ps->postfix)) { | ||
796 | elt = list_first_entry(&ps->postfix, struct postfix_elt, list); | ||
797 | kfree(elt->operand); | ||
798 | list_del(&elt->list); | ||
799 | } | ||
800 | } | ||
801 | |||
802 | static int filter_parse(struct filter_parse_state *ps) | ||
803 | { | ||
804 | int op, top_op; | ||
805 | char ch; | ||
806 | |||
807 | while ((ch = infix_next(ps))) { | ||
808 | if (isspace(ch)) | ||
809 | continue; | ||
810 | |||
811 | if (is_op_char(ps, ch)) { | ||
812 | op = infix_get_op(ps, ch); | ||
813 | if (op == OP_NONE) { | ||
814 | parse_error(ps, FILT_ERR_INVALID_OP, 0); | ||
476 | return -EINVAL; | 815 | return -EINVAL; |
477 | } | 816 | } |
478 | tok_n = 2; | 817 | |
818 | if (strlen(curr_operand(ps))) { | ||
819 | postfix_append_operand(ps, curr_operand(ps)); | ||
820 | clear_operand_string(ps); | ||
821 | } | ||
822 | |||
823 | while (!filter_opstack_empty(ps)) { | ||
824 | top_op = filter_opstack_top(ps); | ||
825 | if (!is_precedence_lower(ps, top_op, op)) { | ||
826 | top_op = filter_opstack_pop(ps); | ||
827 | postfix_append_op(ps, top_op); | ||
828 | continue; | ||
829 | } | ||
830 | break; | ||
831 | } | ||
832 | |||
833 | filter_opstack_push(ps, op); | ||
479 | continue; | 834 | continue; |
480 | } | 835 | } |
481 | if (tok_n == 2) { | 836 | |
482 | if (pred->compound) { | 837 | if (ch == '(') { |
483 | if (!strcmp(tok, "!=")) | 838 | filter_opstack_push(ps, OP_OPEN_PAREN); |
484 | pred->not = 1; | 839 | continue; |
485 | else if (!strcmp(tok, "==")) | 840 | } |
486 | pred->not = 0; | 841 | |
487 | else { | 842 | if (ch == ')') { |
488 | pred->field_name = NULL; | 843 | if (strlen(curr_operand(ps))) { |
489 | return -EINVAL; | 844 | postfix_append_operand(ps, curr_operand(ps)); |
490 | } | 845 | clear_operand_string(ps); |
491 | } else { | 846 | } |
492 | val_str = tok; | 847 | |
493 | break; /* done */ | 848 | top_op = filter_opstack_pop(ps); |
849 | while (top_op != OP_NONE) { | ||
850 | if (top_op == OP_OPEN_PAREN) | ||
851 | break; | ||
852 | postfix_append_op(ps, top_op); | ||
853 | top_op = filter_opstack_pop(ps); | ||
854 | } | ||
855 | if (top_op == OP_NONE) { | ||
856 | parse_error(ps, FILT_ERR_UNBALANCED_PAREN, 0); | ||
857 | return -EINVAL; | ||
494 | } | 858 | } |
495 | tok_n = 3; | ||
496 | continue; | 859 | continue; |
497 | } | 860 | } |
498 | if (tok_n == 3) { | 861 | if (append_operand_char(ps, ch)) { |
499 | val_str = tok; | 862 | parse_error(ps, FILT_ERR_OPERAND_TOO_LONG, 0); |
500 | break; /* done */ | 863 | return -EINVAL; |
864 | } | ||
865 | } | ||
866 | |||
867 | if (strlen(curr_operand(ps))) | ||
868 | postfix_append_operand(ps, curr_operand(ps)); | ||
869 | |||
870 | while (!filter_opstack_empty(ps)) { | ||
871 | top_op = filter_opstack_pop(ps); | ||
872 | if (top_op == OP_NONE) | ||
873 | break; | ||
874 | if (top_op == OP_OPEN_PAREN) { | ||
875 | parse_error(ps, FILT_ERR_UNBALANCED_PAREN, 0); | ||
876 | return -EINVAL; | ||
877 | } | ||
878 | postfix_append_op(ps, top_op); | ||
879 | } | ||
880 | |||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | static struct filter_pred *create_pred(int op, char *operand1, char *operand2) | ||
885 | { | ||
886 | struct filter_pred *pred; | ||
887 | |||
888 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); | ||
889 | if (!pred) | ||
890 | return NULL; | ||
891 | |||
892 | pred->field_name = kstrdup(operand1, GFP_KERNEL); | ||
893 | if (!pred->field_name) { | ||
894 | kfree(pred); | ||
895 | return NULL; | ||
896 | } | ||
897 | |||
898 | strcpy(pred->str_val, operand2); | ||
899 | pred->str_len = strlen(operand2); | ||
900 | |||
901 | pred->op = op; | ||
902 | |||
903 | return pred; | ||
904 | } | ||
905 | |||
906 | static struct filter_pred *create_logical_pred(int op) | ||
907 | { | ||
908 | struct filter_pred *pred; | ||
909 | |||
910 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); | ||
911 | if (!pred) | ||
912 | return NULL; | ||
913 | |||
914 | pred->op = op; | ||
915 | |||
916 | return pred; | ||
917 | } | ||
918 | |||
919 | static int check_preds(struct filter_parse_state *ps) | ||
920 | { | ||
921 | int n_normal_preds = 0, n_logical_preds = 0; | ||
922 | struct postfix_elt *elt; | ||
923 | |||
924 | list_for_each_entry(elt, &ps->postfix, list) { | ||
925 | if (elt->op == OP_NONE) | ||
926 | continue; | ||
927 | |||
928 | if (elt->op == OP_AND || elt->op == OP_OR) { | ||
929 | n_logical_preds++; | ||
930 | continue; | ||
501 | } | 931 | } |
932 | n_normal_preds++; | ||
502 | } | 933 | } |
503 | 934 | ||
504 | if (!val_str || !strlen(val_str) | 935 | if (!n_normal_preds || n_logical_preds >= n_normal_preds) { |
505 | || strlen(val_str) >= MAX_FILTER_STR_VAL) { | 936 | parse_error(ps, FILT_ERR_INVALID_FILTER, 0); |
506 | pred->field_name = NULL; | ||
507 | return -EINVAL; | 937 | return -EINVAL; |
508 | } | 938 | } |
509 | 939 | ||
510 | strcpy(pred->str_val, val_str); | 940 | return 0; |
511 | pred->str_len = strlen(val_str); | 941 | } |
512 | 942 | ||
513 | pred->field_name = kstrdup(pred->field_name, GFP_KERNEL); | 943 | static int replace_preds(struct event_subsystem *system, |
514 | if (!pred->field_name) | 944 | struct ftrace_event_call *call, |
515 | return -ENOMEM; | 945 | struct filter_parse_state *ps, |
946 | char *filter_string) | ||
947 | { | ||
948 | char *operand1 = NULL, *operand2 = NULL; | ||
949 | struct filter_pred *pred; | ||
950 | struct postfix_elt *elt; | ||
951 | int err; | ||
952 | |||
953 | err = check_preds(ps); | ||
954 | if (err) | ||
955 | return err; | ||
956 | |||
957 | list_for_each_entry(elt, &ps->postfix, list) { | ||
958 | if (elt->op == OP_NONE) { | ||
959 | if (!operand1) | ||
960 | operand1 = elt->operand; | ||
961 | else if (!operand2) | ||
962 | operand2 = elt->operand; | ||
963 | else { | ||
964 | parse_error(ps, FILT_ERR_TOO_MANY_OPERANDS, 0); | ||
965 | return -EINVAL; | ||
966 | } | ||
967 | continue; | ||
968 | } | ||
969 | |||
970 | if (elt->op == OP_AND || elt->op == OP_OR) { | ||
971 | pred = create_logical_pred(elt->op); | ||
972 | if (call) { | ||
973 | err = filter_add_pred(ps, call, pred); | ||
974 | filter_free_pred(pred); | ||
975 | } else | ||
976 | err = filter_add_subsystem_pred(ps, system, | ||
977 | pred, filter_string); | ||
978 | if (err) | ||
979 | return err; | ||
980 | |||
981 | operand1 = operand2 = NULL; | ||
982 | continue; | ||
983 | } | ||
984 | |||
985 | if (!operand1 || !operand2) { | ||
986 | parse_error(ps, FILT_ERR_MISSING_FIELD, 0); | ||
987 | return -EINVAL; | ||
988 | } | ||
989 | |||
990 | pred = create_pred(elt->op, operand1, operand2); | ||
991 | if (call) { | ||
992 | err = filter_add_pred(ps, call, pred); | ||
993 | filter_free_pred(pred); | ||
994 | } else | ||
995 | err = filter_add_subsystem_pred(ps, system, pred, | ||
996 | filter_string); | ||
997 | if (err) | ||
998 | return err; | ||
999 | |||
1000 | operand1 = operand2 = NULL; | ||
1001 | } | ||
516 | 1002 | ||
517 | return 0; | 1003 | return 0; |
518 | } | 1004 | } |
519 | 1005 | ||
1006 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | ||
1007 | { | ||
1008 | int err; | ||
1009 | |||
1010 | struct filter_parse_state *ps; | ||
1011 | |||
1012 | mutex_lock(&filter_mutex); | ||
1013 | |||
1014 | if (!strcmp(strstrip(filter_string), "0")) { | ||
1015 | filter_disable_preds(call); | ||
1016 | remove_filter_string(call->filter); | ||
1017 | mutex_unlock(&filter_mutex); | ||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | ps = kzalloc(sizeof(*ps), GFP_KERNEL); | ||
1022 | if (!ps) | ||
1023 | return -ENOMEM; | ||
1024 | |||
1025 | filter_disable_preds(call); | ||
1026 | replace_filter_string(call->filter, filter_string); | ||
1027 | |||
1028 | parse_init(ps, filter_ops, filter_string); | ||
1029 | err = filter_parse(ps); | ||
1030 | if (err) { | ||
1031 | append_filter_err(ps, call->filter); | ||
1032 | goto out; | ||
1033 | } | ||
1034 | |||
1035 | err = replace_preds(NULL, call, ps, filter_string); | ||
1036 | if (err) | ||
1037 | append_filter_err(ps, call->filter); | ||
1038 | |||
1039 | out: | ||
1040 | filter_opstack_clear(ps); | ||
1041 | postfix_clear(ps); | ||
1042 | kfree(ps); | ||
1043 | |||
1044 | mutex_unlock(&filter_mutex); | ||
1045 | |||
1046 | return err; | ||
1047 | } | ||
1048 | |||
1049 | int apply_subsystem_event_filter(struct event_subsystem *system, | ||
1050 | char *filter_string) | ||
1051 | { | ||
1052 | int err; | ||
1053 | |||
1054 | struct filter_parse_state *ps; | ||
1055 | |||
1056 | mutex_lock(&filter_mutex); | ||
1057 | |||
1058 | if (!strcmp(strstrip(filter_string), "0")) { | ||
1059 | filter_free_subsystem_preds(system); | ||
1060 | remove_filter_string(system->filter); | ||
1061 | mutex_unlock(&filter_mutex); | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | ps = kzalloc(sizeof(*ps), GFP_KERNEL); | ||
1066 | if (!ps) | ||
1067 | return -ENOMEM; | ||
1068 | |||
1069 | filter_free_subsystem_preds(system); | ||
1070 | replace_filter_string(system->filter, filter_string); | ||
1071 | |||
1072 | parse_init(ps, filter_ops, filter_string); | ||
1073 | err = filter_parse(ps); | ||
1074 | if (err) { | ||
1075 | append_filter_err(ps, system->filter); | ||
1076 | goto out; | ||
1077 | } | ||
1078 | |||
1079 | err = replace_preds(system, NULL, ps, filter_string); | ||
1080 | if (err) | ||
1081 | append_filter_err(ps, system->filter); | ||
1082 | |||
1083 | out: | ||
1084 | filter_opstack_clear(ps); | ||
1085 | postfix_clear(ps); | ||
1086 | kfree(ps); | ||
1087 | |||
1088 | mutex_unlock(&filter_mutex); | ||
1089 | |||
1090 | return err; | ||
1091 | } | ||
520 | 1092 | ||