Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tracing, perf: Implement BPF programs attached to uprobes

By copying BPF related operation to uprobe processing path, this patch
allow users attach BPF programs to uprobes like what they are already
doing on kprobes.

After this patch, users are allowed to use PERF_EVENT_IOC_SET_BPF on a
uprobe perf event. Which make it possible to profile user space programs
and kernel events together using BPF.

Because of this patch, CONFIG_BPF_EVENTS should be selected by
CONFIG_UPROBE_EVENT to ensure trace_call_bpf() is compiled even if
KPROBE_EVENT is not set.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David Ahern <dsahern@gmail.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kaixu Xia <xiakaixu@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1435716878-189507-3-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
04a22fae 098d2164

+13 -3
+5
include/linux/trace_events.h
··· 243 243 TRACE_EVENT_FL_USE_CALL_FILTER_BIT, 244 244 TRACE_EVENT_FL_TRACEPOINT_BIT, 245 245 TRACE_EVENT_FL_KPROBE_BIT, 246 + TRACE_EVENT_FL_UPROBE_BIT, 246 247 }; 247 248 248 249 /* ··· 258 257 * USE_CALL_FILTER - For trace internal events, don't use file filter 259 258 * TRACEPOINT - Event is a tracepoint 260 259 * KPROBE - Event is a kprobe 260 + * UPROBE - Event is a uprobe 261 261 */ 262 262 enum { 263 263 TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT), ··· 269 267 TRACE_EVENT_FL_USE_CALL_FILTER = (1 << TRACE_EVENT_FL_USE_CALL_FILTER_BIT), 270 268 TRACE_EVENT_FL_TRACEPOINT = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT), 271 269 TRACE_EVENT_FL_KPROBE = (1 << TRACE_EVENT_FL_KPROBE_BIT), 270 + TRACE_EVENT_FL_UPROBE = (1 << TRACE_EVENT_FL_UPROBE_BIT), 272 271 }; 272 + 273 + #define TRACE_EVENT_FL_UKPROBE (TRACE_EVENT_FL_KPROBE | TRACE_EVENT_FL_UPROBE) 273 274 274 275 struct trace_event_call { 275 276 struct list_head list;
+2 -2
kernel/events/core.c
··· 6846 6846 if (event->tp_event->prog) 6847 6847 return -EEXIST; 6848 6848 6849 - if (!(event->tp_event->flags & TRACE_EVENT_FL_KPROBE)) 6850 - /* bpf programs can only be attached to kprobes */ 6849 + if (!(event->tp_event->flags & TRACE_EVENT_FL_UKPROBE)) 6850 + /* bpf programs can only be attached to u/kprobes */ 6851 6851 return -EINVAL; 6852 6852 6853 6853 prog = bpf_prog_get(prog_fd);
+1 -1
kernel/trace/Kconfig
··· 434 434 435 435 config BPF_EVENTS 436 436 depends on BPF_SYSCALL 437 - depends on KPROBE_EVENT 437 + depends on KPROBE_EVENT || UPROBE_EVENT 438 438 bool 439 439 default y 440 440 help
+5
kernel/trace/trace_uprobe.c
··· 1095 1095 { 1096 1096 struct trace_event_call *call = &tu->tp.call; 1097 1097 struct uprobe_trace_entry_head *entry; 1098 + struct bpf_prog *prog = call->prog; 1098 1099 struct hlist_head *head; 1099 1100 void *data; 1100 1101 int size, esize; 1101 1102 int rctx; 1103 + 1104 + if (prog && !trace_call_bpf(prog, regs)) 1105 + return; 1102 1106 1103 1107 esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); 1104 1108 ··· 1293 1289 return -ENODEV; 1294 1290 } 1295 1291 1292 + call->flags = TRACE_EVENT_FL_UPROBE; 1296 1293 call->class->reg = trace_uprobe_register; 1297 1294 call->data = tu; 1298 1295 ret = trace_add_event_call(call);