aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace.h66
-rw-r--r--kernel/trace/trace_events.c86
-rw-r--r--kernel/trace/trace_events_filter.c1020
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 {
735struct event_filter { 735struct 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
740struct event_subsystem { 741struct event_subsystem {
@@ -746,7 +747,8 @@ struct event_subsystem {
746 747
747struct filter_pred; 748struct filter_pred;
748 749
749typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event); 750typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
751 int val1, int val2);
750 752
751struct filter_pred { 753struct 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
764extern void filter_free_pred(struct filter_pred *pred); 765extern void print_event_filter(struct ftrace_event_call *call,
765extern void filter_print_preds(struct ftrace_event_call *call,
766 struct trace_seq *s); 766 struct trace_seq *s);
767extern int filter_parse(char **pbuf, struct filter_pred *pred); 767extern int apply_event_filter(struct ftrace_event_call *call,
768extern int filter_add_pred(struct ftrace_event_call *call, 768 char *filter_string);
769 struct filter_pred *pred); 769extern int apply_subsystem_event_filter(struct event_subsystem *system,
770extern void filter_disable_preds(struct ftrace_event_call *call); 770 char *filter_string);
771extern void filter_free_subsystem_preds(struct event_subsystem *system); 771extern void print_subsystem_event_filter(struct event_subsystem *system,
772extern void filter_print_subsystem_preds(struct event_subsystem *system,
773 struct trace_seq *s); 772 struct trace_seq *s);
774extern int filter_add_subsystem_pred(struct event_subsystem *system,
775 struct filter_pred *pred);
776 773
777static inline int 774static inline int
778filter_check_discard(struct ftrace_event_call *call, void *rec, 775filter_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) \
788static 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) \
816static 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
790extern struct list_head ftrace_events; 828extern struct list_head ftrace_events;
791 829
792extern const char *__start___trace_bprintk_fmt[]; 830extern 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
30static DEFINE_MUTEX(filter_mutex); 30static DEFINE_MUTEX(filter_mutex);
31 31
32static int filter_pred_64(struct filter_pred *pred, void *event) 32enum 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,
43static 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; 46struct 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} 52static struct filter_op filter_ops[] = {
53 53 { OP_OR, "||", 1 },
54static 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
65enum {
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
80static 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
95struct opstack_op {
96 int op;
97 struct list_head list;
98};
99
100struct postfix_elt {
101 int op;
102 char *operand;
103 struct list_head list;
104};
105
106struct 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
126DEFINE_COMPARISON_PRED(s64);
127DEFINE_COMPARISON_PRED(u64);
128DEFINE_COMPARISON_PRED(s32);
129DEFINE_COMPARISON_PRED(u32);
130DEFINE_COMPARISON_PRED(s16);
131DEFINE_COMPARISON_PRED(u16);
132DEFINE_COMPARISON_PRED(s8);
133DEFINE_COMPARISON_PRED(u8);
134
135DEFINE_EQUALITY_PRED(64);
136DEFINE_EQUALITY_PRED(32);
137DEFINE_EQUALITY_PRED(16);
138DEFINE_EQUALITY_PRED(8);
139
140static 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
65static int filter_pred_8(struct filter_pred *pred, void *event) 147static 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
76static int filter_pred_string(struct filter_pred *pred, void *event) 154static 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
88static int filter_pred_none(struct filter_pred *pred, void *event) 167static 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)
94int filter_match_preds(struct ftrace_event_call *call, void *rec) 174int 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}
117EXPORT_SYMBOL_GPL(filter_match_preds); 201EXPORT_SYMBOL_GPL(filter_match_preds);
118 202
119static void __filter_print_preds(struct event_filter *filter, 203static 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) { 209static 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
215static 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
226static 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
246static 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
145void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s) 268void 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
152void filter_print_subsystem_preds(struct event_subsystem *system, 280void 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
173void filter_free_pred(struct filter_pred *pred) 306static 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
202static void __filter_disable_preds(struct ftrace_event_call *call) 337static 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
214void 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
221int init_preds(struct ftrace_event_call *call) 349int 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}
259EXPORT_SYMBOL_GPL(init_preds); 387EXPORT_SYMBOL_GPL(init_preds);
260 388
261static void __filter_free_subsystem_preds(struct event_subsystem *system) 389static 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
284void filter_free_subsystem_preds(struct event_subsystem *system) 414static 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
291static 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
324static int __filter_add_pred(struct ftrace_event_call *call, 447static 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
455static 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
498static 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
368int 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
379int filter_add_subsystem_pred(struct event_subsystem *system, 555static 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
600static 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
614static char infix_next(struct filter_parse_state *ps)
615{
616 ps->infix.cnt--;
617
618 return ps->infix.string[ps->infix.tail++];
619}
620
621static 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
629static void infix_advance(struct filter_parse_state *ps)
630{
631 ps->infix.cnt--;
632 ps->infix.tail++;
633}
634
635static 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
641static 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/* 653static 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;
446int 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
680static 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
686static 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
696static 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
710static int filter_opstack_empty(struct filter_parse_state *ps)
711{
712 return list_empty(&ps->opstack);
713}
714
715static 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
727static 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
744static void filter_opstack_clear(struct filter_parse_state *ps)
745{
746 while (!filter_opstack_empty(ps))
747 filter_opstack_pop(ps);
748}
749
750static char *curr_operand(struct filter_parse_state *ps)
751{
752 return ps->operand.string;
753}
754
755static 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
775static 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
791static 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
802static 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
884static 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
906static 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
919static 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); 943static 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
1006int 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
1039out:
1040 filter_opstack_clear(ps);
1041 postfix_clear(ps);
1042 kfree(ps);
1043
1044 mutex_unlock(&filter_mutex);
1045
1046 return err;
1047}
1048
1049int 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
1083out:
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