aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/trace/trace.h15
-rw-r--r--kernel/trace/trace_events.c86
-rw-r--r--kernel/trace/trace_events_filter.c80
3 files changed, 175 insertions, 6 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index d9eb39e4bb38..f267723c3c52 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -804,6 +804,18 @@ struct ftrace_event_call {
804#endif 804#endif
805}; 805};
806 806
807struct event_subsystem {
808 struct list_head list;
809 const char *name;
810 struct dentry *entry;
811 struct filter_pred **preds;
812};
813
814#define events_for_each(event) \
815 for (event = __start_ftrace_events; \
816 (unsigned long)event < (unsigned long)__stop_ftrace_events; \
817 event++)
818
807#define MAX_FILTER_PRED 8 819#define MAX_FILTER_PRED 8
808 820
809struct filter_pred; 821struct filter_pred;
@@ -832,6 +844,9 @@ extern int filter_add_pred(struct ftrace_event_call *call,
832 struct filter_pred *pred); 844 struct filter_pred *pred);
833extern void filter_free_preds(struct ftrace_event_call *call); 845extern void filter_free_preds(struct ftrace_event_call *call);
834extern int filter_match_preds(struct ftrace_event_call *call, void *rec); 846extern int filter_match_preds(struct ftrace_event_call *call, void *rec);
847extern void filter_free_subsystem_preds(struct event_subsystem *system);
848extern int filter_add_subsystem_pred(struct event_subsystem *system,
849 struct filter_pred *pred);
835 850
836void event_trace_printk(unsigned long ip, const char *fmt, ...); 851void event_trace_printk(unsigned long ip, const char *fmt, ...);
837extern struct ftrace_event_call __start_ftrace_events[]; 852extern struct ftrace_event_call __start_ftrace_events[];
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
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 8e8c5fa25be9..1ab20cee0e4c 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -181,6 +181,27 @@ void filter_free_preds(struct ftrace_event_call *call)
181 } 181 }
182} 182}
183 183
184void filter_free_subsystem_preds(struct event_subsystem *system)
185{
186 struct ftrace_event_call *call = __start_ftrace_events;
187 int i;
188
189 if (system->preds) {
190 for (i = 0; i < MAX_FILTER_PRED; i++)
191 filter_free_pred(system->preds[i]);
192 kfree(system->preds);
193 system->preds = NULL;
194 }
195
196 events_for_each(call) {
197 if (!call->name || !call->regfunc)
198 continue;
199
200 if (!strcmp(call->system, system->name))
201 filter_free_preds(call);
202 }
203}
204
184static int __filter_add_pred(struct ftrace_event_call *call, 205static int __filter_add_pred(struct ftrace_event_call *call,
185 struct filter_pred *pred) 206 struct filter_pred *pred)
186{ 207{
@@ -250,6 +271,65 @@ int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
250 return __filter_add_pred(call, pred); 271 return __filter_add_pred(call, pred);
251} 272}
252 273
274static struct filter_pred *copy_pred(struct filter_pred *pred)
275{
276 struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL);
277 if (!new_pred)
278 return NULL;
279
280 memcpy(new_pred, pred, sizeof(*pred));
281 if (pred->str_val) {
282 new_pred->str_val = kstrdup(pred->str_val, GFP_KERNEL);
283 new_pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
284 if (!new_pred->str_val) {
285 kfree(new_pred);
286 return NULL;
287 }
288 }
289
290 return new_pred;
291}
292
293int filter_add_subsystem_pred(struct event_subsystem *system,
294 struct filter_pred *pred)
295{
296 struct ftrace_event_call *call = __start_ftrace_events;
297 struct filter_pred *event_pred;
298 int i;
299
300 if (system->preds && !pred->compound)
301 filter_free_subsystem_preds(system);
302
303 if (!system->preds) {
304 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
305 GFP_KERNEL);
306 if (!system->preds)
307 return -ENOMEM;
308 }
309
310 for (i = 0; i < MAX_FILTER_PRED; i++) {
311 if (!system->preds[i]) {
312 system->preds[i] = pred;
313 break;
314 }
315 if (i == MAX_FILTER_PRED - 1)
316 return -EINVAL;
317 }
318
319 events_for_each(call) {
320 if (!call->name || !call->regfunc)
321 continue;
322
323 if (!strcmp(call->system, system->name)) {
324 event_pred = copy_pred(pred);
325 if (event_pred)
326 filter_add_pred(call, event_pred);
327 }
328 }
329
330 return 0;
331}
332
253int filter_parse(char **pbuf, struct filter_pred *pred) 333int filter_parse(char **pbuf, struct filter_pred *pred)
254{ 334{
255 char *tmp, *tok, *val_str = NULL; 335 char *tmp, *tok, *val_str = NULL;