aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLi Zefan <lizf@cn.fujitsu.com>2009-10-14 23:21:42 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-15 05:35:23 -0400
commit6fb2915df7f0747d9044da9dbff5b46dc2e20830 (patch)
treeb4c5d7d913362ae6161c2859a7a385263330e965 /kernel
parentb0f1a59a98d7ac2102e7e4f22904c26d564a5628 (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.c80
-rw-r--r--kernel/trace/trace.h3
-rw-r--r--kernel/trace/trace_events_filter.c133
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
1662static void perf_event_free_filter(struct perf_event *event);
1663
1661static void free_event_rcu(struct rcu_head *head) 1664static 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
1977int perf_event_set_output(struct perf_event *event, int output_fd); 1981static int perf_event_set_output(struct perf_event *event, int output_fd);
1982static int perf_event_set_filter(struct perf_event *event, void __user *arg);
1978 1983
1979static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1984static 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
3817static int perf_tp_event_match(struct perf_event *event,
3818 struct perf_sample_data *data);
3819
3809static int perf_swevent_match(struct perf_event *event, 3820static 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
4089void perf_tp_event(int event_id, u64 addr, u64 count, void *record, 4107void 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}
4110EXPORT_SYMBOL_GPL(perf_tp_event); 4128EXPORT_SYMBOL_GPL(perf_tp_event);
4111 4129
4112extern int ftrace_profile_enable(int); 4130static int perf_tp_event_match(struct perf_event *event,
4113extern 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
4115static void tp_perf_event_destroy(struct perf_event *event) 4140static 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
4164static 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
4182static void perf_event_free_filter(struct perf_event *event)
4183{
4184 ftrace_profile_free_filter(event);
4185}
4186
4138#else 4187#else
4188
4189static int perf_tp_event_match(struct perf_event *event,
4190 struct perf_sample_data *data)
4191{
4192 return 1;
4193}
4194
4139static const struct pmu *tp_perf_event_init(struct perf_event *event) 4195static const struct pmu *tp_perf_event_init(struct perf_event *event)
4140{ 4196{
4141 return NULL; 4197 return NULL;
4142} 4198}
4143#endif 4199
4200static int perf_event_set_filter(struct perf_event *event, void __user *arg)
4201{
4202 return -ENOENT;
4203}
4204
4205static void perf_event_free_filter(struct perf_event *event)
4206{
4207}
4208
4209#endif /* CONFIG_EVENT_PROFILE */
4144 4210
4145atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; 4211atomic_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
4397int perf_event_set_output(struct perf_event *event, int output_fd) 4463static 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) */
366int filter_match_preds(struct ftrace_event_call *call, void *rec) 367int 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
541void destroy_preds(struct ftrace_event_call *call) 541static 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
557void 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
559static int init_preds(struct ftrace_event_call *call) 564static 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
588oom: 590oom:
589 destroy_preds(call); 591 __free_preds(filter);
592 return ERR_PTR(-ENOMEM);
593}
594
595static 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
594static int init_subsystem_preds(struct event_subsystem *system) 608static int init_subsystem_preds(struct event_subsystem *system)
@@ -629,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
629 643
630static int filter_add_pred_fn(struct filter_parse_state *ps, 644static 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
727static int filter_add_pred(struct filter_parse_state *ps, 740static 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
796add_pred_fn: 810add_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
1156static int replace_preds(struct ftrace_event_call *call, 1170static 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,
1200add_pred: 1215add_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,
1252int apply_event_filter(struct ftrace_event_call *call, char *filter_string) 1270int 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;
1290out: 1308out:
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
1367void 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
1375int 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
1413free_ps:
1414 filter_opstack_clear(ps);
1415 postfix_clear(ps);
1416 kfree(ps);
1417
1418free_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