aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2015-09-25 12:58:44 -0400
committerSteven Rostedt <rostedt@goodmis.org>2015-10-25 21:33:56 -0400
commit3fdaf80f4a836911c0eda1cee92f8aa625f90197 (patch)
tree02a11349dcf8c02f58af1e2823c61bff8062fbbb
parent4909010788640b7101bf50cddb7c5e60172b4433 (diff)
tracing: Implement event pid filtering
Add the necessary hooks to use the pids loaded in set_event_pid to filter all the events enabled in the tracing instance that match the pids listed. Two probes are added to both sched_switch and sched_wakeup tracepoints to be called before other probes are called and after the other probes are called. The first is used to set the necessary flags to let the probes know to test if they should be traced or not. The sched_switch pre probe will set the "ignore_pid" flag if neither the previous or next task has a matching pid. The sched_switch probe will set the "ignore_pid" flag if the next task does not match the matching pid. The pre probe allows for probes tracing sched_switch to be traced if necessary. The sched_wakeup pre probe will set the "ignore_pid" flag if neither the current task nor the wakee task has a matching pid. The sched_wakeup post probe will set the "ignore_pid" flag if the current task does not have a matching pid. Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--include/linux/trace_events.h7
-rw-r--r--kernel/trace/trace.h2
-rw-r--r--kernel/trace/trace_events.c148
3 files changed, 154 insertions, 3 deletions
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index f85693bbcdc3..429fdfc3baf5 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -328,6 +328,7 @@ enum {
328 EVENT_FILE_FL_SOFT_DISABLED_BIT, 328 EVENT_FILE_FL_SOFT_DISABLED_BIT,
329 EVENT_FILE_FL_TRIGGER_MODE_BIT, 329 EVENT_FILE_FL_TRIGGER_MODE_BIT,
330 EVENT_FILE_FL_TRIGGER_COND_BIT, 330 EVENT_FILE_FL_TRIGGER_COND_BIT,
331 EVENT_FILE_FL_PID_FILTER_BIT,
331}; 332};
332 333
333/* 334/*
@@ -341,6 +342,7 @@ enum {
341 * tracepoint may be enabled) 342 * tracepoint may be enabled)
342 * TRIGGER_MODE - When set, invoke the triggers associated with the event 343 * TRIGGER_MODE - When set, invoke the triggers associated with the event
343 * TRIGGER_COND - When set, one or more triggers has an associated filter 344 * TRIGGER_COND - When set, one or more triggers has an associated filter
345 * PID_FILTER - When set, the event is filtered based on pid
344 */ 346 */
345enum { 347enum {
346 EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT), 348 EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT),
@@ -351,6 +353,7 @@ enum {
351 EVENT_FILE_FL_SOFT_DISABLED = (1 << EVENT_FILE_FL_SOFT_DISABLED_BIT), 353 EVENT_FILE_FL_SOFT_DISABLED = (1 << EVENT_FILE_FL_SOFT_DISABLED_BIT),
352 EVENT_FILE_FL_TRIGGER_MODE = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT), 354 EVENT_FILE_FL_TRIGGER_MODE = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT),
353 EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT), 355 EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT),
356 EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT),
354}; 357};
355 358
356struct trace_event_file { 359struct trace_event_file {
@@ -429,6 +432,8 @@ extern enum event_trigger_type event_triggers_call(struct trace_event_file *file
429extern void event_triggers_post_call(struct trace_event_file *file, 432extern void event_triggers_post_call(struct trace_event_file *file,
430 enum event_trigger_type tt); 433 enum event_trigger_type tt);
431 434
435bool trace_event_ignore_this_pid(struct trace_event_file *trace_file);
436
432/** 437/**
433 * trace_trigger_soft_disabled - do triggers and test if soft disabled 438 * trace_trigger_soft_disabled - do triggers and test if soft disabled
434 * @file: The file pointer of the event to test 439 * @file: The file pointer of the event to test
@@ -448,6 +453,8 @@ trace_trigger_soft_disabled(struct trace_event_file *file)
448 event_triggers_call(file, NULL); 453 event_triggers_call(file, NULL);
449 if (eflags & EVENT_FILE_FL_SOFT_DISABLED) 454 if (eflags & EVENT_FILE_FL_SOFT_DISABLED)
450 return true; 455 return true;
456 if (eflags & EVENT_FILE_FL_PID_FILTER)
457 return trace_event_ignore_this_pid(file);
451 } 458 }
452 return false; 459 return false;
453} 460}
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 250481043bb5..89ffdaf3e371 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -156,6 +156,8 @@ struct trace_array_cpu {
156 pid_t pid; 156 pid_t pid;
157 kuid_t uid; 157 kuid_t uid;
158 char comm[TASK_COMM_LEN]; 158 char comm[TASK_COMM_LEN];
159
160 bool ignore_pid;
159}; 161};
160 162
161struct tracer; 163struct tracer;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 2ad7014707ee..ab07058e27c1 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -22,6 +22,8 @@
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/delay.h> 23#include <linux/delay.h>
24 24
25#include <trace/events/sched.h>
26
25#include <asm/setup.h> 27#include <asm/setup.h>
26 28
27#include "trace_output.h" 29#include "trace_output.h"
@@ -212,12 +214,32 @@ int trace_event_raw_init(struct trace_event_call *call)
212} 214}
213EXPORT_SYMBOL_GPL(trace_event_raw_init); 215EXPORT_SYMBOL_GPL(trace_event_raw_init);
214 216
217bool trace_event_ignore_this_pid(struct trace_event_file *trace_file)
218{
219 struct trace_array *tr = trace_file->tr;
220 struct trace_array_cpu *data;
221 struct trace_pid_list *pid_list;
222
223 pid_list = rcu_dereference_sched(tr->filtered_pids);
224 if (!pid_list)
225 return false;
226
227 data = this_cpu_ptr(tr->trace_buffer.data);
228
229 return data->ignore_pid;
230}
231EXPORT_SYMBOL_GPL(trace_event_ignore_this_pid);
232
215void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer, 233void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,
216 struct trace_event_file *trace_file, 234 struct trace_event_file *trace_file,
217 unsigned long len) 235 unsigned long len)
218{ 236{
219 struct trace_event_call *event_call = trace_file->event_call; 237 struct trace_event_call *event_call = trace_file->event_call;
220 238
239 if ((trace_file->flags & EVENT_FILE_FL_PID_FILTER) &&
240 trace_event_ignore_this_pid(trace_file))
241 return NULL;
242
221 local_save_flags(fbuffer->flags); 243 local_save_flags(fbuffer->flags);
222 fbuffer->pc = preempt_count(); 244 fbuffer->pc = preempt_count();
223 fbuffer->trace_file = trace_file; 245 fbuffer->trace_file = trace_file;
@@ -459,15 +481,114 @@ static int cmp_pid(const void *key, const void *elt)
459 return 1; 481 return 1;
460} 482}
461 483
484static bool
485check_ignore_pid(struct trace_pid_list *filtered_pids, struct task_struct *task)
486{
487 pid_t search_pid;
488 pid_t *pid;
489
490 /*
491 * Return false, because if filtered_pids does not exist,
492 * all pids are good to trace.
493 */
494 if (!filtered_pids)
495 return false;
496
497 search_pid = task->pid;
498
499 pid = bsearch(&search_pid, filtered_pids->pids,
500 filtered_pids->nr_pids, sizeof(pid_t),
501 cmp_pid);
502 if (!pid)
503 return true;
504
505 return false;
506}
507
508static void
509event_filter_pid_sched_switch_probe_pre(void *data,
510 struct task_struct *prev, struct task_struct *next)
511{
512 struct trace_array *tr = data;
513 struct trace_pid_list *pid_list;
514
515 pid_list = rcu_dereference_sched(tr->filtered_pids);
516
517 this_cpu_write(tr->trace_buffer.data->ignore_pid,
518 check_ignore_pid(pid_list, prev) &&
519 check_ignore_pid(pid_list, next));
520}
521
522static void
523event_filter_pid_sched_switch_probe_post(void *data,
524 struct task_struct *prev, struct task_struct *next)
525{
526 struct trace_array *tr = data;
527 struct trace_pid_list *pid_list;
528
529 pid_list = rcu_dereference_sched(tr->filtered_pids);
530
531 this_cpu_write(tr->trace_buffer.data->ignore_pid,
532 check_ignore_pid(pid_list, next));
533}
534
535static void
536event_filter_pid_sched_wakeup_probe_pre(void *data, struct task_struct *task)
537{
538 struct trace_array *tr = data;
539 struct trace_pid_list *pid_list;
540
541 /* Nothing to do if we are already tracing */
542 if (!this_cpu_read(tr->trace_buffer.data->ignore_pid))
543 return;
544
545 pid_list = rcu_dereference_sched(tr->filtered_pids);
546
547 this_cpu_write(tr->trace_buffer.data->ignore_pid,
548 check_ignore_pid(pid_list, task));
549}
550
551static void
552event_filter_pid_sched_wakeup_probe_post(void *data, struct task_struct *task)
553{
554 struct trace_array *tr = data;
555 struct trace_pid_list *pid_list;
556
557 /* Nothing to do if we are not tracing */
558 if (this_cpu_read(tr->trace_buffer.data->ignore_pid))
559 return;
560
561 pid_list = rcu_dereference_sched(tr->filtered_pids);
562
563 /* Set tracing if current is enabled */
564 this_cpu_write(tr->trace_buffer.data->ignore_pid,
565 check_ignore_pid(pid_list, current));
566}
567
462static void __ftrace_clear_event_pids(struct trace_array *tr) 568static void __ftrace_clear_event_pids(struct trace_array *tr)
463{ 569{
464 struct trace_pid_list *pid_list; 570 struct trace_pid_list *pid_list;
571 struct trace_event_file *file;
572 int cpu;
465 573
466 pid_list = rcu_dereference_protected(tr->filtered_pids, 574 pid_list = rcu_dereference_protected(tr->filtered_pids,
467 lockdep_is_held(&event_mutex)); 575 lockdep_is_held(&event_mutex));
468 if (!pid_list) 576 if (!pid_list)
469 return; 577 return;
470 578
579 unregister_trace_sched_switch(event_filter_pid_sched_switch_probe_pre, tr);
580 unregister_trace_sched_switch(event_filter_pid_sched_switch_probe_post, tr);
581
582 unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre, tr);
583 unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_post, tr);
584
585 list_for_each_entry(file, &tr->events, list) {
586 clear_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
587 }
588
589 for_each_possible_cpu(cpu)
590 per_cpu_ptr(tr->trace_buffer.data, cpu)->ignore_pid = false;
591
471 rcu_assign_pointer(tr->filtered_pids, NULL); 592 rcu_assign_pointer(tr->filtered_pids, NULL);
472 593
473 /* Wait till all users are no longer using pid filtering */ 594 /* Wait till all users are no longer using pid filtering */
@@ -1429,13 +1550,14 @@ static int max_pids(struct trace_pid_list *pid_list)
1429} 1550}
1430 1551
1431static ssize_t 1552static ssize_t
1432ftrace_event_pid_write(struct file *file, const char __user *ubuf, 1553ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
1433 size_t cnt, loff_t *ppos) 1554 size_t cnt, loff_t *ppos)
1434{ 1555{
1435 struct seq_file *m = file->private_data; 1556 struct seq_file *m = filp->private_data;
1436 struct trace_array *tr = m->private; 1557 struct trace_array *tr = m->private;
1437 struct trace_pid_list *filtered_pids = NULL; 1558 struct trace_pid_list *filtered_pids = NULL;
1438 struct trace_pid_list *pid_list = NULL; 1559 struct trace_pid_list *pid_list = NULL;
1560 struct trace_event_file *file;
1439 struct trace_parser parser; 1561 struct trace_parser parser;
1440 unsigned long val; 1562 unsigned long val;
1441 loff_t this_pos; 1563 loff_t this_pos;
@@ -1564,15 +1686,35 @@ ftrace_event_pid_write(struct file *file, const char __user *ubuf,
1564 1686
1565 rcu_assign_pointer(tr->filtered_pids, pid_list); 1687 rcu_assign_pointer(tr->filtered_pids, pid_list);
1566 1688
1567 mutex_unlock(&event_mutex); 1689 list_for_each_entry(file, &tr->events, list) {
1690 set_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
1691 }
1568 1692
1569 if (filtered_pids) { 1693 if (filtered_pids) {
1570 synchronize_sched(); 1694 synchronize_sched();
1571 1695
1572 free_pages((unsigned long)filtered_pids->pids, filtered_pids->order); 1696 free_pages((unsigned long)filtered_pids->pids, filtered_pids->order);
1573 kfree(filtered_pids); 1697 kfree(filtered_pids);
1698 } else {
1699 /*
1700 * Register a probe that is called before all other probes
1701 * to set ignore_pid if next or prev do not match.
1702 * Register a probe this is called after all other probes
1703 * to only keep ignore_pid set if next pid matches.
1704 */
1705 register_trace_prio_sched_switch(event_filter_pid_sched_switch_probe_pre,
1706 tr, INT_MAX);
1707 register_trace_prio_sched_switch(event_filter_pid_sched_switch_probe_post,
1708 tr, 0);
1709
1710 register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre,
1711 tr, INT_MAX);
1712 register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_post,
1713 tr, 0);
1574 } 1714 }
1575 1715
1716 mutex_unlock(&event_mutex);
1717
1576 ret = read; 1718 ret = read;
1577 *ppos += read; 1719 *ppos += read;
1578 1720