Skip to content

Commit b91e014

Browse files
author
Alexei Starovoitov
committed
bpf: Make BPF trampoline use register_ftrace_direct() API
Make BPF trampoline attach its generated assembly code to kernel functions via register_ftrace_direct() API. It helps ftrace-based tracers co-exist with BPF trampoline on the same kernel function. It also switches attaching logic from arch specific text_poke to generic ftrace that is available on many architectures. text_poke is still necessary for bpf-to-bpf attach and for bpf_tail_call optimization. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/20191209000114.1876138-3-ast@kernel.org
1 parent 5b79bcd commit b91e014

File tree

2 files changed

+59
-6
lines changed

2 files changed

+59
-6
lines changed

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ struct bpf_trampoline {
461461
struct {
462462
struct btf_func_model model;
463463
void *addr;
464+
bool ftrace_managed;
464465
} func;
465466
/* list of BPF programs using this trampoline */
466467
struct hlist_head progs_hlist[BPF_TRAMP_MAX];

kernel/bpf/trampoline.c

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/hash.h>
44
#include <linux/bpf.h>
55
#include <linux/filter.h>
6+
#include <linux/ftrace.h>
67

78
/* btf_vmlinux has ~22k attachable functions. 1k htab is enough. */
89
#define TRAMPOLINE_HASH_BITS 10
@@ -59,6 +60,60 @@ struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
5960
return tr;
6061
}
6162

63+
static int is_ftrace_location(void *ip)
64+
{
65+
long addr;
66+
67+
addr = ftrace_location((long)ip);
68+
if (!addr)
69+
return 0;
70+
if (WARN_ON_ONCE(addr != (long)ip))
71+
return -EFAULT;
72+
return 1;
73+
}
74+
75+
static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
76+
{
77+
void *ip = tr->func.addr;
78+
int ret;
79+
80+
if (tr->func.ftrace_managed)
81+
ret = unregister_ftrace_direct((long)ip, (long)old_addr);
82+
else
83+
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
84+
return ret;
85+
}
86+
87+
static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_addr)
88+
{
89+
void *ip = tr->func.addr;
90+
int ret;
91+
92+
if (tr->func.ftrace_managed)
93+
ret = modify_ftrace_direct((long)ip, (long)old_addr, (long)new_addr);
94+
else
95+
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, new_addr);
96+
return ret;
97+
}
98+
99+
/* first time registering */
100+
static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
101+
{
102+
void *ip = tr->func.addr;
103+
int ret;
104+
105+
ret = is_ftrace_location(ip);
106+
if (ret < 0)
107+
return ret;
108+
tr->func.ftrace_managed = ret;
109+
110+
if (tr->func.ftrace_managed)
111+
ret = register_ftrace_direct((long)ip, (long)new_addr);
112+
else
113+
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
114+
return ret;
115+
}
116+
62117
/* Each call __bpf_prog_enter + call bpf_func + call __bpf_prog_exit is ~50
63118
* bytes on x86. Pick a number to fit into PAGE_SIZE / 2
64119
*/
@@ -77,8 +132,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr)
77132
int err;
78133

79134
if (fentry_cnt + fexit_cnt == 0) {
80-
err = bpf_arch_text_poke(tr->func.addr, BPF_MOD_CALL,
81-
old_image, NULL);
135+
err = unregister_fentry(tr, old_image);
82136
tr->selector = 0;
83137
goto out;
84138
}
@@ -105,12 +159,10 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr)
105159

106160
if (tr->selector)
107161
/* progs already running at this address */
108-
err = bpf_arch_text_poke(tr->func.addr, BPF_MOD_CALL,
109-
old_image, new_image);
162+
err = modify_fentry(tr, old_image, new_image);
110163
else
111164
/* first time registering */
112-
err = bpf_arch_text_poke(tr->func.addr, BPF_MOD_CALL, NULL,
113-
new_image);
165+
err = register_fentry(tr, new_image);
114166
if (err)
115167
goto out;
116168
tr->selector++;

0 commit comments

Comments
 (0)