aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_events.c
diff options
context:
space:
mode:
authorTom Zanussi <tzanussi@gmail.com>2009-03-22 04:31:17 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-22 13:38:47 -0400
commitcfb180f3e71b2a280a254c8646a9ab1beab63f84 (patch)
tree93fb1a319b40851ebb7a3cc0d9ea4cc9a88e919a /kernel/trace/trace_events.c
parent7ce7e4249921d5073e764f7ff7ad83cfa9894bd7 (diff)
tracing: add per-subsystem filtering
This patch adds per-subsystem filtering to the event tracing subsystem. It adds a 'filter' debugfs file to each subsystem directory. This file can be written to to set filters; reading from it will display the current set of filters set for that subsystem. Basically what it does is propagate the filter down to each event contained in the subsystem. If a particular event doesn't have a field with the name specified in the filter, it simply doesn't get set for that event. You can verify whether or not the filter was set for a particular event by looking at the filter file for that event. As with per-event filters, compound expressions are supported, echoing '0' to the subsystem's filter file clears all filters in the subsystem, etc. Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Acked-by: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <1237710677.7703.49.camel@charm-linux> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r--kernel/trace/trace_events.c86
1 files changed, 80 insertions, 6 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 97470c48956e..97d4daaddd9a 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -524,6 +524,71 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
524 return cnt; 524 return cnt;
525} 525}
526 526
527static ssize_t
528subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
529 loff_t *ppos)
530{
531 struct event_subsystem *system = filp->private_data;
532 struct trace_seq *s;
533 int r;
534
535 if (*ppos)
536 return 0;
537
538 s = kmalloc(sizeof(*s), GFP_KERNEL);
539 if (!s)
540 return -ENOMEM;
541
542 trace_seq_init(s);
543
544 r = filter_print_preds(system->preds, s->buffer);
545 r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, r);
546
547 kfree(s);
548
549 return r;
550}
551
552static ssize_t
553subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
554 loff_t *ppos)
555{
556 struct event_subsystem *system = filp->private_data;
557 char buf[64], *pbuf = buf;
558 struct filter_pred *pred;
559 int err;
560
561 if (cnt >= sizeof(buf))
562 return -EINVAL;
563
564 if (copy_from_user(&buf, ubuf, cnt))
565 return -EFAULT;
566
567 pred = kzalloc(sizeof(*pred), GFP_KERNEL);
568 if (!pred)
569 return -ENOMEM;
570
571 err = filter_parse(&pbuf, pred);
572 if (err < 0) {
573 filter_free_pred(pred);
574 return err;
575 }
576
577 if (pred->clear) {
578 filter_free_subsystem_preds(system);
579 return cnt;
580 }
581
582 if (filter_add_subsystem_pred(system, pred)) {
583 filter_free_pred(pred);
584 return -EINVAL;
585 }
586
587 *ppos += cnt;
588
589 return cnt;
590}
591
527static const struct seq_operations show_event_seq_ops = { 592static const struct seq_operations show_event_seq_ops = {
528 .start = t_start, 593 .start = t_start,
529 .next = t_next, 594 .next = t_next,
@@ -575,6 +640,12 @@ static const struct file_operations ftrace_event_filter_fops = {
575 .write = event_filter_write, 640 .write = event_filter_write,
576}; 641};
577 642
643static const struct file_operations ftrace_subsystem_filter_fops = {
644 .open = tracing_open_generic,
645 .read = subsystem_filter_read,
646 .write = subsystem_filter_write,
647};
648
578static struct dentry *event_trace_events_dir(void) 649static struct dentry *event_trace_events_dir(void)
579{ 650{
580 static struct dentry *d_tracer; 651 static struct dentry *d_tracer;
@@ -595,18 +666,13 @@ static struct dentry *event_trace_events_dir(void)
595 return d_events; 666 return d_events;
596} 667}
597 668
598struct event_subsystem {
599 struct list_head list;
600 const char *name;
601 struct dentry *entry;
602};
603
604static LIST_HEAD(event_subsystems); 669static LIST_HEAD(event_subsystems);
605 670
606static struct dentry * 671static struct dentry *
607event_subsystem_dir(const char *name, struct dentry *d_events) 672event_subsystem_dir(const char *name, struct dentry *d_events)
608{ 673{
609 struct event_subsystem *system; 674 struct event_subsystem *system;
675 struct dentry *entry;
610 676
611 /* First see if we did not already create this dir */ 677 /* First see if we did not already create this dir */
612 list_for_each_entry(system, &event_subsystems, list) { 678 list_for_each_entry(system, &event_subsystems, list) {
@@ -633,6 +699,14 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
633 system->name = name; 699 system->name = name;
634 list_add(&system->list, &event_subsystems); 700 list_add(&system->list, &event_subsystems);
635 701
702 system->preds = NULL;
703
704 entry = debugfs_create_file("filter", 0444, system->entry, system,
705 &ftrace_subsystem_filter_fops);
706 if (!entry)
707 pr_warning("Could not create debugfs "
708 "'%s/filter' entry\n", name);
709
636 return system->entry; 710 return system->entry;
637} 711}
638 712