[ftrace-bpf 2/5] add bpf prog interface for ftrace
From: yupeng0921
Date: Sun Nov 12 2017 - 02:28:51 EST
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: yupeng0921@xxxxxxxxx
---
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