diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2009-10-14 23:21:42 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-10-15 05:35:23 -0400 |
commit | 6fb2915df7f0747d9044da9dbff5b46dc2e20830 (patch) | |
tree | b4c5d7d913362ae6161c2859a7a385263330e965 /kernel | |
parent | b0f1a59a98d7ac2102e7e4f22904c26d564a5628 (diff) |
tracing/profile: Add filter support
- Add an ioctl to allocate a filter for a perf event.
- Free the filter when the associated perf event is to be freed.
- Do the filtering in perf_swevent_match().
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4AD69546.8050401@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_event.c | 80 | ||||
-rw-r--r-- | kernel/trace/trace.h | 3 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 133 |
3 files changed, 182 insertions, 34 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 9d0b5c665883..12b5ec39bf97 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/anon_inodes.h> | 28 | #include <linux/anon_inodes.h> |
29 | #include <linux/kernel_stat.h> | 29 | #include <linux/kernel_stat.h> |
30 | #include <linux/perf_event.h> | 30 | #include <linux/perf_event.h> |
31 | #include <linux/ftrace_event.h> | ||
31 | 32 | ||
32 | #include <asm/irq_regs.h> | 33 | #include <asm/irq_regs.h> |
33 | 34 | ||
@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu) | |||
1658 | return ERR_PTR(err); | 1659 | return ERR_PTR(err); |
1659 | } | 1660 | } |
1660 | 1661 | ||
1662 | static void perf_event_free_filter(struct perf_event *event); | ||
1663 | |||
1661 | static void free_event_rcu(struct rcu_head *head) | 1664 | static void free_event_rcu(struct rcu_head *head) |
1662 | { | 1665 | { |
1663 | struct perf_event *event; | 1666 | struct perf_event *event; |
@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head) | |||
1665 | event = container_of(head, struct perf_event, rcu_head); | 1668 | event = container_of(head, struct perf_event, rcu_head); |
1666 | if (event->ns) | 1669 | if (event->ns) |
1667 | put_pid_ns(event->ns); | 1670 | put_pid_ns(event->ns); |
1671 | perf_event_free_filter(event); | ||
1668 | kfree(event); | 1672 | kfree(event); |
1669 | } | 1673 | } |
1670 | 1674 | ||
@@ -1974,7 +1978,8 @@ unlock: | |||
1974 | return ret; | 1978 | return ret; |
1975 | } | 1979 | } |
1976 | 1980 | ||
1977 | int perf_event_set_output(struct perf_event *event, int output_fd); | 1981 | static int perf_event_set_output(struct perf_event *event, int output_fd); |
1982 | static int perf_event_set_filter(struct perf_event *event, void __user *arg); | ||
1978 | 1983 | ||
1979 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1984 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1980 | { | 1985 | { |
@@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2002 | case PERF_EVENT_IOC_SET_OUTPUT: | 2007 | case PERF_EVENT_IOC_SET_OUTPUT: |
2003 | return perf_event_set_output(event, arg); | 2008 | return perf_event_set_output(event, arg); |
2004 | 2009 | ||
2010 | case PERF_EVENT_IOC_SET_FILTER: | ||
2011 | return perf_event_set_filter(event, (void __user *)arg); | ||
2012 | |||
2005 | default: | 2013 | default: |
2006 | return -ENOTTY; | 2014 | return -ENOTTY; |
2007 | } | 2015 | } |
@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event) | |||
3806 | return 1; | 3814 | return 1; |
3807 | } | 3815 | } |
3808 | 3816 | ||
3817 | static int perf_tp_event_match(struct perf_event *event, | ||
3818 | struct perf_sample_data *data); | ||
3819 | |||
3809 | static int perf_swevent_match(struct perf_event *event, | 3820 | static int perf_swevent_match(struct perf_event *event, |
3810 | enum perf_type_id type, | 3821 | enum perf_type_id type, |
3811 | u32 event_id, struct pt_regs *regs) | 3822 | u32 event_id, |
3823 | struct perf_sample_data *data, | ||
3824 | struct pt_regs *regs) | ||
3812 | { | 3825 | { |
3813 | if (!perf_swevent_is_counting(event)) | 3826 | if (!perf_swevent_is_counting(event)) |
3814 | return 0; | 3827 | return 0; |
@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event, | |||
3826 | return 0; | 3839 | return 0; |
3827 | } | 3840 | } |
3828 | 3841 | ||
3842 | if (event->attr.type == PERF_TYPE_TRACEPOINT && | ||
3843 | !perf_tp_event_match(event, data)) | ||
3844 | return 0; | ||
3845 | |||
3829 | return 1; | 3846 | return 1; |
3830 | } | 3847 | } |
3831 | 3848 | ||
@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx, | |||
3842 | 3859 | ||
3843 | rcu_read_lock(); | 3860 | rcu_read_lock(); |
3844 | list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { | 3861 | list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { |
3845 | if (perf_swevent_match(event, type, event_id, regs)) | 3862 | if (perf_swevent_match(event, type, event_id, data, regs)) |
3846 | perf_swevent_add(event, nr, nmi, data, regs); | 3863 | perf_swevent_add(event, nr, nmi, data, regs); |
3847 | } | 3864 | } |
3848 | rcu_read_unlock(); | 3865 | rcu_read_unlock(); |
@@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = { | |||
4086 | }; | 4103 | }; |
4087 | 4104 | ||
4088 | #ifdef CONFIG_EVENT_PROFILE | 4105 | #ifdef CONFIG_EVENT_PROFILE |
4106 | |||
4089 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 4107 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, |
4090 | int entry_size) | 4108 | int entry_size) |
4091 | { | 4109 | { |
@@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | |||
4109 | } | 4127 | } |
4110 | EXPORT_SYMBOL_GPL(perf_tp_event); | 4128 | EXPORT_SYMBOL_GPL(perf_tp_event); |
4111 | 4129 | ||
4112 | extern int ftrace_profile_enable(int); | 4130 | static int perf_tp_event_match(struct perf_event *event, |
4113 | extern void ftrace_profile_disable(int); | 4131 | struct perf_sample_data *data) |
4132 | { | ||
4133 | void *record = data->raw->data; | ||
4134 | |||
4135 | if (likely(!event->filter) || filter_match_preds(event->filter, record)) | ||
4136 | return 1; | ||
4137 | return 0; | ||
4138 | } | ||
4114 | 4139 | ||
4115 | static void tp_perf_event_destroy(struct perf_event *event) | 4140 | static void tp_perf_event_destroy(struct perf_event *event) |
4116 | { | 4141 | { |
@@ -4135,12 +4160,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event) | |||
4135 | 4160 | ||
4136 | return &perf_ops_generic; | 4161 | return &perf_ops_generic; |
4137 | } | 4162 | } |
4163 | |||
4164 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | ||
4165 | { | ||
4166 | char *filter_str; | ||
4167 | int ret; | ||
4168 | |||
4169 | if (event->attr.type != PERF_TYPE_TRACEPOINT) | ||
4170 | return -EINVAL; | ||
4171 | |||
4172 | filter_str = strndup_user(arg, PAGE_SIZE); | ||
4173 | if (IS_ERR(filter_str)) | ||
4174 | return PTR_ERR(filter_str); | ||
4175 | |||
4176 | ret = ftrace_profile_set_filter(event, event->attr.config, filter_str); | ||
4177 | |||
4178 | kfree(filter_str); | ||
4179 | return ret; | ||
4180 | } | ||
4181 | |||
4182 | static void perf_event_free_filter(struct perf_event *event) | ||
4183 | { | ||
4184 | ftrace_profile_free_filter(event); | ||
4185 | } | ||
4186 | |||
4138 | #else | 4187 | #else |
4188 | |||
4189 | static int perf_tp_event_match(struct perf_event *event, | ||
4190 | struct perf_sample_data *data) | ||
4191 | { | ||
4192 | return 1; | ||
4193 | } | ||
4194 | |||
4139 | static const struct pmu *tp_perf_event_init(struct perf_event *event) | 4195 | static const struct pmu *tp_perf_event_init(struct perf_event *event) |
4140 | { | 4196 | { |
4141 | return NULL; | 4197 | return NULL; |
4142 | } | 4198 | } |
4143 | #endif | 4199 | |
4200 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | ||
4201 | { | ||
4202 | return -ENOENT; | ||
4203 | } | ||
4204 | |||
4205 | static void perf_event_free_filter(struct perf_event *event) | ||
4206 | { | ||
4207 | } | ||
4208 | |||
4209 | #endif /* CONFIG_EVENT_PROFILE */ | ||
4144 | 4210 | ||
4145 | atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; | 4211 | atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; |
4146 | 4212 | ||
@@ -4394,7 +4460,7 @@ err_size: | |||
4394 | goto out; | 4460 | goto out; |
4395 | } | 4461 | } |
4396 | 4462 | ||
4397 | int perf_event_set_output(struct perf_event *event, int output_fd) | 4463 | static int perf_event_set_output(struct perf_event *event, int output_fd) |
4398 | { | 4464 | { |
4399 | struct perf_event *output_event = NULL; | 4465 | struct perf_event *output_event = NULL; |
4400 | struct file *output_file = NULL; | 4466 | struct file *output_file = NULL; |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index ffe53ddbe67a..4959ada9e0bb 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -743,7 +743,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec, | |||
743 | struct ring_buffer *buffer, | 743 | struct ring_buffer *buffer, |
744 | struct ring_buffer_event *event) | 744 | struct ring_buffer_event *event) |
745 | { | 745 | { |
746 | if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) { | 746 | if (unlikely(call->filter_active) && |
747 | !filter_match_preds(call->filter, rec)) { | ||
747 | ring_buffer_discard_commit(buffer, event); | 748 | ring_buffer_discard_commit(buffer, event); |
748 | return 1; | 749 | return 1; |
749 | } | 750 | } |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 273845fce393..e27bb6acc2dd 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/perf_event.h> | ||
24 | 25 | ||
25 | #include "trace.h" | 26 | #include "trace.h" |
26 | #include "trace_output.h" | 27 | #include "trace_output.h" |
@@ -363,9 +364,8 @@ static void filter_build_regex(struct filter_pred *pred) | |||
363 | } | 364 | } |
364 | 365 | ||
365 | /* return 1 if event matches, 0 otherwise (discard) */ | 366 | /* return 1 if event matches, 0 otherwise (discard) */ |
366 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 367 | int filter_match_preds(struct event_filter *filter, void *rec) |
367 | { | 368 | { |
368 | struct event_filter *filter = call->filter; | ||
369 | int match, top = 0, val1 = 0, val2 = 0; | 369 | int match, top = 0, val1 = 0, val2 = 0; |
370 | int stack[MAX_FILTER_PRED]; | 370 | int stack[MAX_FILTER_PRED]; |
371 | struct filter_pred *pred; | 371 | struct filter_pred *pred; |
@@ -538,9 +538,8 @@ static void filter_disable_preds(struct ftrace_event_call *call) | |||
538 | filter->preds[i]->fn = filter_pred_none; | 538 | filter->preds[i]->fn = filter_pred_none; |
539 | } | 539 | } |
540 | 540 | ||
541 | void destroy_preds(struct ftrace_event_call *call) | 541 | static void __free_preds(struct event_filter *filter) |
542 | { | 542 | { |
543 | struct event_filter *filter = call->filter; | ||
544 | int i; | 543 | int i; |
545 | 544 | ||
546 | if (!filter) | 545 | if (!filter) |
@@ -553,21 +552,24 @@ void destroy_preds(struct ftrace_event_call *call) | |||
553 | kfree(filter->preds); | 552 | kfree(filter->preds); |
554 | kfree(filter->filter_string); | 553 | kfree(filter->filter_string); |
555 | kfree(filter); | 554 | kfree(filter); |
555 | } | ||
556 | |||
557 | void destroy_preds(struct ftrace_event_call *call) | ||
558 | { | ||
559 | __free_preds(call->filter); | ||
556 | call->filter = NULL; | 560 | call->filter = NULL; |
561 | call->filter_active = 0; | ||
557 | } | 562 | } |
558 | 563 | ||
559 | static int init_preds(struct ftrace_event_call *call) | 564 | static struct event_filter *__alloc_preds(void) |
560 | { | 565 | { |
561 | struct event_filter *filter; | 566 | struct event_filter *filter; |
562 | struct filter_pred *pred; | 567 | struct filter_pred *pred; |
563 | int i; | 568 | int i; |
564 | 569 | ||
565 | if (call->filter) | 570 | filter = kzalloc(sizeof(*filter), GFP_KERNEL); |
566 | return 0; | 571 | if (!filter) |
567 | 572 | return ERR_PTR(-ENOMEM); | |
568 | filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL); | ||
569 | if (!call->filter) | ||
570 | return -ENOMEM; | ||
571 | 573 | ||
572 | filter->n_preds = 0; | 574 | filter->n_preds = 0; |
573 | 575 | ||
@@ -583,12 +585,24 @@ static int init_preds(struct ftrace_event_call *call) | |||
583 | filter->preds[i] = pred; | 585 | filter->preds[i] = pred; |
584 | } | 586 | } |
585 | 587 | ||
586 | return 0; | 588 | return filter; |
587 | 589 | ||
588 | oom: | 590 | oom: |
589 | destroy_preds(call); | 591 | __free_preds(filter); |
592 | return ERR_PTR(-ENOMEM); | ||
593 | } | ||
594 | |||
595 | static int init_preds(struct ftrace_event_call *call) | ||
596 | { | ||
597 | if (call->filter) | ||
598 | return 0; | ||
599 | |||
600 | call->filter_active = 0; | ||
601 | call->filter = __alloc_preds(); | ||
602 | if (IS_ERR(call->filter)) | ||
603 | return PTR_ERR(call->filter); | ||
590 | 604 | ||
591 | return -ENOMEM; | 605 | return 0; |
592 | } | 606 | } |
593 | 607 | ||
594 | static int init_subsystem_preds(struct event_subsystem *system) | 608 | static int init_subsystem_preds(struct event_subsystem *system) |
@@ -629,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system) | |||
629 | 643 | ||
630 | static int filter_add_pred_fn(struct filter_parse_state *ps, | 644 | static int filter_add_pred_fn(struct filter_parse_state *ps, |
631 | struct ftrace_event_call *call, | 645 | struct ftrace_event_call *call, |
646 | struct event_filter *filter, | ||
632 | struct filter_pred *pred, | 647 | struct filter_pred *pred, |
633 | filter_pred_fn_t fn) | 648 | filter_pred_fn_t fn) |
634 | { | 649 | { |
635 | struct event_filter *filter = call->filter; | ||
636 | int idx, err; | 650 | int idx, err; |
637 | 651 | ||
638 | if (filter->n_preds == MAX_FILTER_PRED) { | 652 | if (filter->n_preds == MAX_FILTER_PRED) { |
@@ -647,7 +661,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps, | |||
647 | return err; | 661 | return err; |
648 | 662 | ||
649 | filter->n_preds++; | 663 | filter->n_preds++; |
650 | call->filter_active = 1; | ||
651 | 664 | ||
652 | return 0; | 665 | return 0; |
653 | } | 666 | } |
@@ -726,6 +739,7 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size, | |||
726 | 739 | ||
727 | static int filter_add_pred(struct filter_parse_state *ps, | 740 | static int filter_add_pred(struct filter_parse_state *ps, |
728 | struct ftrace_event_call *call, | 741 | struct ftrace_event_call *call, |
742 | struct event_filter *filter, | ||
729 | struct filter_pred *pred, | 743 | struct filter_pred *pred, |
730 | bool dry_run) | 744 | bool dry_run) |
731 | { | 745 | { |
@@ -795,7 +809,7 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
795 | 809 | ||
796 | add_pred_fn: | 810 | add_pred_fn: |
797 | if (!dry_run) | 811 | if (!dry_run) |
798 | return filter_add_pred_fn(ps, call, pred, fn); | 812 | return filter_add_pred_fn(ps, call, filter, pred, fn); |
799 | return 0; | 813 | return 0; |
800 | } | 814 | } |
801 | 815 | ||
@@ -1154,6 +1168,7 @@ static int check_preds(struct filter_parse_state *ps) | |||
1154 | } | 1168 | } |
1155 | 1169 | ||
1156 | static int replace_preds(struct ftrace_event_call *call, | 1170 | static int replace_preds(struct ftrace_event_call *call, |
1171 | struct event_filter *filter, | ||
1157 | struct filter_parse_state *ps, | 1172 | struct filter_parse_state *ps, |
1158 | char *filter_string, | 1173 | char *filter_string, |
1159 | bool dry_run) | 1174 | bool dry_run) |
@@ -1200,7 +1215,7 @@ static int replace_preds(struct ftrace_event_call *call, | |||
1200 | add_pred: | 1215 | add_pred: |
1201 | if (!pred) | 1216 | if (!pred) |
1202 | return -ENOMEM; | 1217 | return -ENOMEM; |
1203 | err = filter_add_pred(ps, call, pred, dry_run); | 1218 | err = filter_add_pred(ps, call, filter, pred, dry_run); |
1204 | filter_free_pred(pred); | 1219 | filter_free_pred(pred); |
1205 | if (err) | 1220 | if (err) |
1206 | return err; | 1221 | return err; |
@@ -1216,6 +1231,7 @@ static int replace_system_preds(struct event_subsystem *system, | |||
1216 | char *filter_string) | 1231 | char *filter_string) |
1217 | { | 1232 | { |
1218 | struct ftrace_event_call *call; | 1233 | struct ftrace_event_call *call; |
1234 | struct event_filter *filter; | ||
1219 | int err; | 1235 | int err; |
1220 | bool fail = true; | 1236 | bool fail = true; |
1221 | 1237 | ||
@@ -1228,17 +1244,19 @@ static int replace_system_preds(struct event_subsystem *system, | |||
1228 | continue; | 1244 | continue; |
1229 | 1245 | ||
1230 | /* try to see if the filter can be applied */ | 1246 | /* try to see if the filter can be applied */ |
1231 | err = replace_preds(call, ps, filter_string, true); | 1247 | err = replace_preds(call, filter, ps, filter_string, true); |
1232 | if (err) | 1248 | if (err) |
1233 | continue; | 1249 | continue; |
1234 | 1250 | ||
1235 | /* really apply the filter */ | 1251 | /* really apply the filter */ |
1236 | filter_disable_preds(call); | 1252 | filter_disable_preds(call); |
1237 | err = replace_preds(call, ps, filter_string, false); | 1253 | err = replace_preds(call, filter, ps, filter_string, false); |
1238 | if (err) | 1254 | if (err) |
1239 | filter_disable_preds(call); | 1255 | filter_disable_preds(call); |
1240 | else | 1256 | else { |
1241 | replace_filter_string(call->filter, filter_string); | 1257 | call->filter_active = 1; |
1258 | replace_filter_string(filter, filter_string); | ||
1259 | } | ||
1242 | fail = false; | 1260 | fail = false; |
1243 | } | 1261 | } |
1244 | 1262 | ||
@@ -1252,7 +1270,6 @@ static int replace_system_preds(struct event_subsystem *system, | |||
1252 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | 1270 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) |
1253 | { | 1271 | { |
1254 | int err; | 1272 | int err; |
1255 | |||
1256 | struct filter_parse_state *ps; | 1273 | struct filter_parse_state *ps; |
1257 | 1274 | ||
1258 | mutex_lock(&event_mutex); | 1275 | mutex_lock(&event_mutex); |
@@ -1283,10 +1300,11 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
1283 | goto out; | 1300 | goto out; |
1284 | } | 1301 | } |
1285 | 1302 | ||
1286 | err = replace_preds(call, ps, filter_string, false); | 1303 | err = replace_preds(call, call->filter, ps, filter_string, false); |
1287 | if (err) | 1304 | if (err) |
1288 | append_filter_err(ps, call->filter); | 1305 | append_filter_err(ps, call->filter); |
1289 | 1306 | else | |
1307 | call->filter_active = 1; | ||
1290 | out: | 1308 | out: |
1291 | filter_opstack_clear(ps); | 1309 | filter_opstack_clear(ps); |
1292 | postfix_clear(ps); | 1310 | postfix_clear(ps); |
@@ -1301,7 +1319,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
1301 | char *filter_string) | 1319 | char *filter_string) |
1302 | { | 1320 | { |
1303 | int err; | 1321 | int err; |
1304 | |||
1305 | struct filter_parse_state *ps; | 1322 | struct filter_parse_state *ps; |
1306 | 1323 | ||
1307 | mutex_lock(&event_mutex); | 1324 | mutex_lock(&event_mutex); |
@@ -1345,3 +1362,67 @@ out_unlock: | |||
1345 | return err; | 1362 | return err; |
1346 | } | 1363 | } |
1347 | 1364 | ||
1365 | #ifdef CONFIG_EVENT_PROFILE | ||
1366 | |||
1367 | void ftrace_profile_free_filter(struct perf_event *event) | ||
1368 | { | ||
1369 | struct event_filter *filter = event->filter; | ||
1370 | |||
1371 | event->filter = NULL; | ||
1372 | __free_preds(filter); | ||
1373 | } | ||
1374 | |||
1375 | int ftrace_profile_set_filter(struct perf_event *event, int event_id, | ||
1376 | char *filter_str) | ||
1377 | { | ||
1378 | int err; | ||
1379 | struct event_filter *filter; | ||
1380 | struct filter_parse_state *ps; | ||
1381 | struct ftrace_event_call *call = NULL; | ||
1382 | |||
1383 | mutex_lock(&event_mutex); | ||
1384 | |||
1385 | list_for_each_entry(call, &ftrace_events, list) { | ||
1386 | if (call->id == event_id) | ||
1387 | break; | ||
1388 | } | ||
1389 | if (!call) | ||
1390 | return -EINVAL; | ||
1391 | |||
1392 | if (event->filter) | ||
1393 | return -EEXIST; | ||
1394 | |||
1395 | filter = __alloc_preds(); | ||
1396 | if (IS_ERR(filter)) | ||
1397 | return PTR_ERR(filter); | ||
1398 | |||
1399 | err = -ENOMEM; | ||
1400 | ps = kzalloc(sizeof(*ps), GFP_KERNEL); | ||
1401 | if (!ps) | ||
1402 | goto free_preds; | ||
1403 | |||
1404 | parse_init(ps, filter_ops, filter_str); | ||
1405 | err = filter_parse(ps); | ||
1406 | if (err) | ||
1407 | goto free_ps; | ||
1408 | |||
1409 | err = replace_preds(call, filter, ps, filter_str, false); | ||
1410 | if (!err) | ||
1411 | event->filter = filter; | ||
1412 | |||
1413 | free_ps: | ||
1414 | filter_opstack_clear(ps); | ||
1415 | postfix_clear(ps); | ||
1416 | kfree(ps); | ||
1417 | |||
1418 | free_preds: | ||
1419 | if (err) | ||
1420 | __free_preds(filter); | ||
1421 | |||
1422 | mutex_unlock(&event_mutex); | ||
1423 | |||
1424 | return err; | ||
1425 | } | ||
1426 | |||
1427 | #endif /* CONFIG_EVENT_PROFILE */ | ||
1428 | |||