create ftrace_bpf_filter in tracefs, to set a bpf filter, write a bpf prog file descriptor to this file, to clean the bpf filter, write empty string to this file.
Signed-off-by: yupeng0...@gmail.com --- include/linux/ftrace.h | 3 ++ kernel/trace/ftrace.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/trace/trace.c | 6 ++++ kernel/trace/trace.h | 4 +++ 4 files changed, 87 insertions(+) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index e54d257..9959435 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -769,6 +769,9 @@ static inline void ftrace_init(void) { } struct ftrace_graph_ent { unsigned long func; /* Current function */ int depth; +#ifdef FTRACE_BPF_FILTER + struct ftrace_regs *ctx; +#endif } __packed; /* diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8319e09..acb73f6 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -33,6 +33,7 @@ #include <linux/list.h> #include <linux/hash.h> #include <linux/rcupdate.h> +#include <linux/bpf.h> #include <trace/events/sched.h> @@ -6415,10 +6416,83 @@ static const struct file_operations ftrace_pid_fops = { .release = ftrace_pid_release, }; +#ifdef FTRACE_BPF_FILTER +static int +ftrace_bpf_open(struct inode *inode, struct file *file) +{ + struct trace_array *tr = inode->i_private; + + if (trace_array_get(tr) < 0) + return -ENODEV; + + file->private_data = tr; + + return 0; +} + +static int +ftrace_bpf_release(struct inode *inode, struct file *file) +{ + struct trace_array *tr = inode->i_private; + + trace_array_put(tr); + return 0; +} + +static ssize_t +ftrace_bpf_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct trace_array *tr = filp->private_data; + unsigned long prog_fd; + struct bpf_prog *prog, *old_prog; + ssize_t ret = 0; + + old_prog = NULL; + mutex_lock(&ftrace_lock); + if (!cnt) { + old_prog = tr->prog; + goto out; + } + ret = kstrtoul_from_user(ubuf, cnt, 10, &prog_fd); + if (ret) + goto out; + + prog = bpf_prog_get(prog_fd); + if (IS_ERR(prog)) { + ret = PTR_ERR(prog); + goto out; + } + + old_prog = tr->prog; + rcu_assign_pointer(tr->prog, prog); + + out: + mutex_unlock(&ftrace_lock); + if (old_prog) { + synchronize_rcu(); + bpf_prog_put(old_prog); + } + if (ret) + return ret; + + return cnt; +} + +static const struct file_operations ftrace_bpf_fops = { + .open = ftrace_bpf_open, + .write = ftrace_bpf_write, + .release = ftrace_bpf_release, +}; +#endif /* FTRACE_BPF_FILTER */ void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer) { trace_create_file("set_ftrace_pid", 0644, d_tracer, tr, &ftrace_pid_fops); +#ifdef FTRACE_BPF_FILTER + trace_create_file("set_ftrace_bpf", 0644, d_tracer, + tr, &ftrace_bpf_fops); +#endif } void __init ftrace_init_tracefs_toplevel(struct trace_array *tr, diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 752e5da..09c75c7 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -7714,6 +7714,9 @@ static int instance_mkdir(const char *name) raw_spin_lock_init(&tr->start_lock); tr->max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; +#ifdef FTRACE_BPF_FILTER + tr->prog = NULL; +#endif tr->current_trace = &nop_trace; @@ -8354,6 +8357,9 @@ __init static int tracer_alloc_buffers(void) global_trace.current_trace = &nop_trace; global_trace.max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; +#ifdef FTRACE_BPF_FILTER + global_trace.prog = NULL; +#endif ftrace_init_global_array_ops(&global_trace); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 401b063..dedecd6 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -17,6 +17,7 @@ #include <linux/compiler.h> #include <linux/trace_seq.h> #include <linux/glob.h> +#include <linux/filter.h> #ifdef CONFIG_FTRACE_SYSCALLS #include <asm/unistd.h> /* For NR_SYSCALLS */ @@ -261,6 +262,9 @@ struct trace_array { struct list_head events; cpumask_var_t tracing_cpumask; /* only trace on set CPUs */ int ref; +#ifdef FTRACE_BPF_FILTER + struct bpf_prog __rcu *prog; +#endif #ifdef CONFIG_FUNCTION_TRACER struct ftrace_ops *ops; struct trace_pid_list __rcu *function_pids; -- 2.7.4