|
@@ -42,6 +42,8 @@
|
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
|
#include <linux/mman.h>
|
|
#include <linux/mman.h>
|
|
|
#include <linux/compat.h>
|
|
#include <linux/compat.h>
|
|
|
|
|
+#include <linux/bpf.h>
|
|
|
|
|
+#include <linux/filter.h>
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
#include "internal.h"
|
|
|
|
|
|
|
@@ -3407,6 +3409,7 @@ errout:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void perf_event_free_filter(struct perf_event *event);
|
|
static void perf_event_free_filter(struct perf_event *event);
|
|
|
|
|
+static void perf_event_free_bpf_prog(struct perf_event *event);
|
|
|
|
|
|
|
|
static void free_event_rcu(struct rcu_head *head)
|
|
static void free_event_rcu(struct rcu_head *head)
|
|
|
{
|
|
{
|
|
@@ -3416,6 +3419,7 @@ static void free_event_rcu(struct rcu_head *head)
|
|
|
if (event->ns)
|
|
if (event->ns)
|
|
|
put_pid_ns(event->ns);
|
|
put_pid_ns(event->ns);
|
|
|
perf_event_free_filter(event);
|
|
perf_event_free_filter(event);
|
|
|
|
|
+ perf_event_free_bpf_prog(event);
|
|
|
kfree(event);
|
|
kfree(event);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -3928,6 +3932,7 @@ static inline int perf_fget_light(int fd, struct fd *p)
|
|
|
static int perf_event_set_output(struct perf_event *event,
|
|
static int perf_event_set_output(struct perf_event *event,
|
|
|
struct perf_event *output_event);
|
|
struct perf_event *output_event);
|
|
|
static int perf_event_set_filter(struct perf_event *event, void __user *arg);
|
|
static int perf_event_set_filter(struct perf_event *event, void __user *arg);
|
|
|
|
|
+static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd);
|
|
|
|
|
|
|
|
static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned long arg)
|
|
static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
{
|
|
@@ -3981,6 +3986,9 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon
|
|
|
case PERF_EVENT_IOC_SET_FILTER:
|
|
case PERF_EVENT_IOC_SET_FILTER:
|
|
|
return perf_event_set_filter(event, (void __user *)arg);
|
|
return perf_event_set_filter(event, (void __user *)arg);
|
|
|
|
|
|
|
|
|
|
+ case PERF_EVENT_IOC_SET_BPF:
|
|
|
|
|
+ return perf_event_set_bpf_prog(event, arg);
|
|
|
|
|
+
|
|
|
default:
|
|
default:
|
|
|
return -ENOTTY;
|
|
return -ENOTTY;
|
|
|
}
|
|
}
|
|
@@ -6455,6 +6463,49 @@ static void perf_event_free_filter(struct perf_event *event)
|
|
|
ftrace_profile_free_filter(event);
|
|
ftrace_profile_free_filter(event);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bpf_prog *prog;
|
|
|
|
|
+
|
|
|
|
|
+ if (event->attr.type != PERF_TYPE_TRACEPOINT)
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+
|
|
|
|
|
+ if (event->tp_event->prog)
|
|
|
|
|
+ return -EEXIST;
|
|
|
|
|
+
|
|
|
|
|
+ if (!(event->tp_event->flags & TRACE_EVENT_FL_KPROBE))
|
|
|
|
|
+ /* bpf programs can only be attached to kprobes */
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+
|
|
|
|
|
+ prog = bpf_prog_get(prog_fd);
|
|
|
|
|
+ if (IS_ERR(prog))
|
|
|
|
|
+ return PTR_ERR(prog);
|
|
|
|
|
+
|
|
|
|
|
+ if (prog->aux->prog_type != BPF_PROG_TYPE_KPROBE) {
|
|
|
|
|
+ /* valid fd, but invalid bpf program type */
|
|
|
|
|
+ bpf_prog_put(prog);
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ event->tp_event->prog = prog;
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void perf_event_free_bpf_prog(struct perf_event *event)
|
|
|
|
|
+{
|
|
|
|
|
+ struct bpf_prog *prog;
|
|
|
|
|
+
|
|
|
|
|
+ if (!event->tp_event)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ prog = event->tp_event->prog;
|
|
|
|
|
+ if (prog) {
|
|
|
|
|
+ event->tp_event->prog = NULL;
|
|
|
|
|
+ bpf_prog_put(prog);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
#else
|
|
#else
|
|
|
|
|
|
|
|
static inline void perf_tp_register(void)
|
|
static inline void perf_tp_register(void)
|
|
@@ -6470,6 +6521,14 @@ static void perf_event_free_filter(struct perf_event *event)
|
|
|
{
|
|
{
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
|
|
|
|
|
+{
|
|
|
|
|
+ return -ENOENT;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void perf_event_free_bpf_prog(struct perf_event *event)
|
|
|
|
|
+{
|
|
|
|
|
+}
|
|
|
#endif /* CONFIG_EVENT_TRACING */
|
|
#endif /* CONFIG_EVENT_TRACING */
|
|
|
|
|
|
|
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|