Skip to content

Commit 3f33906

Browse files
olsajiriKernel Patches Daemon
authored andcommitted
bpf, x86: Use single ftrace_ops for direct calls
Using single ftrace_ops for direct calls update instead of allocating ftrace_ops obejct for each trampoline. At the moment we can enable this only on x86 arch, because arm relies on ftrace_ops object representing just single trampoline image (stored in ftrace_ops::direct_call). Adding HAVE_SINGLE_FTRACE_DIRECT_OPS config option to be enabled on each arch that supports this. Signed-off-by: Jiri Olsa <[email protected]>
1 parent 95ef19f commit 3f33906

File tree

4 files changed

+92
-12
lines changed

4 files changed

+92
-12
lines changed

arch/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ config X86
330330
imply IMA_SECURE_AND_OR_TRUSTED_BOOT if EFI
331331
select HAVE_DYNAMIC_FTRACE_NO_PATCHABLE
332332
select ARCH_SUPPORTS_PT_RECLAIM if X86_64
333+
select HAVE_SINGLE_FTRACE_DIRECT_OPS if X86_64 && DYNAMIC_FTRACE_WITH_DIRECT_CALLS
333334

334335
config INSTRUCTION_DECODER
335336
def_bool y

kernel/bpf/trampoline.c

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,40 @@ static DEFINE_MUTEX(trampoline_mutex);
3333
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
3434
static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mutex);
3535

36+
#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
37+
static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
38+
{
39+
struct hlist_head *head_ip;
40+
struct bpf_trampoline *tr;
41+
42+
mutex_lock(&trampoline_mutex);
43+
head_ip = &trampoline_ip_table[hash_64(ip, TRAMPOLINE_HASH_BITS)];
44+
hlist_for_each_entry(tr, head_ip, hlist_ip) {
45+
if (tr->func.addr == (void *) ip)
46+
goto out;
47+
}
48+
tr = NULL;
49+
out:
50+
mutex_unlock(&trampoline_mutex);
51+
return tr;
52+
}
53+
#else
54+
static struct bpf_trampoline *direct_ops_ip_lookup(struct ftrace_ops *ops, unsigned long ip)
55+
{
56+
return ops->private;
57+
}
58+
#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
59+
3660
static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, unsigned long ip,
3761
enum ftrace_ops_cmd cmd)
3862
{
39-
struct bpf_trampoline *tr = ops->private;
63+
struct bpf_trampoline *tr;
4064
int ret = 0;
4165

66+
tr = direct_ops_ip_lookup(ops, ip);
67+
if (!tr)
68+
return -EINVAL;
69+
4270
if (cmd == FTRACE_OPS_CMD_ENABLE_SHARE_IPMODIFY_SELF) {
4371
/* This is called inside register_ftrace_direct_multi(), so
4472
* tr->mutex is already locked.
@@ -137,6 +165,48 @@ void bpf_image_ksym_del(struct bpf_ksym *ksym)
137165
PAGE_SIZE, true, ksym->name);
138166
}
139167

168+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
169+
#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
170+
struct ftrace_ops direct_ops = {
171+
.ops_func = bpf_tramp_ftrace_ops_func,
172+
};
173+
174+
static int direct_ops_get(struct bpf_trampoline *tr)
175+
{
176+
tr->fops = &direct_ops;
177+
return 0;
178+
}
179+
static void direct_ops_clear(struct bpf_trampoline *tr) { }
180+
static void direct_ops_free(struct bpf_trampoline *tr) { }
181+
#else
182+
static int direct_ops_get(struct bpf_trampoline *tr)
183+
{
184+
tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
185+
if (!tr->fops)
186+
return -1;
187+
tr->fops->private = tr;
188+
tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
189+
return 0;
190+
}
191+
192+
static void direct_ops_clear(struct bpf_trampoline *tr)
193+
{
194+
tr->fops->func = NULL;
195+
tr->fops->trampoline = 0;
196+
}
197+
198+
static void direct_ops_free(struct bpf_trampoline *tr)
199+
{
200+
if (tr->fops) {
201+
ftrace_free_filter(tr->fops);
202+
kfree(tr->fops);
203+
}
204+
}
205+
#endif /* CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS */
206+
#else
207+
static void direct_ops_free(struct bpf_trampoline *tr) { }
208+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
209+
140210
static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
141211
{
142212
struct bpf_trampoline *tr;
@@ -155,14 +225,11 @@ static struct bpf_trampoline *bpf_trampoline_lookup(u64 key, unsigned long ip)
155225
if (!tr)
156226
goto out;
157227
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
158-
tr->fops = kzalloc(sizeof(struct ftrace_ops), GFP_KERNEL);
159-
if (!tr->fops) {
228+
if (direct_ops_get(tr)) {
160229
kfree(tr);
161230
tr = NULL;
162231
goto out;
163232
}
164-
tr->fops->private = tr;
165-
tr->fops->ops_func = bpf_tramp_ftrace_ops_func;
166233
#endif
167234

168235
tr->key = key;
@@ -482,8 +549,7 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
482549
* trampoline again, and retry register.
483550
*/
484551
/* reset fops->func and fops->trampoline for re-register */
485-
tr->fops->func = NULL;
486-
tr->fops->trampoline = 0;
552+
direct_ops_clear(tr);
487553

488554
/* free im memory and reallocate later */
489555
bpf_tramp_image_free(im);
@@ -864,10 +930,7 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
864930
*/
865931
hlist_del(&tr->hlist_key);
866932
hlist_del(&tr->hlist_ip);
867-
if (tr->fops) {
868-
ftrace_free_filter(tr->fops);
869-
kfree(tr->fops);
870-
}
933+
direct_ops_free(tr);
871934
kfree(tr);
872935
out:
873936
mutex_unlock(&trampoline_mutex);

kernel/trace/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
5050
config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
5151
bool
5252

53+
config HAVE_SINGLE_FTRACE_DIRECT_OPS
54+
bool
55+
5356
config HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS
5457
bool
5558

kernel/trace/ftrace.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2592,8 +2592,13 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
25922592
static void call_direct_funcs(unsigned long ip, unsigned long pip,
25932593
struct ftrace_ops *ops, struct ftrace_regs *fregs)
25942594
{
2595-
unsigned long addr = READ_ONCE(ops->direct_call);
2595+
unsigned long addr;
25962596

2597+
#ifdef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
2598+
addr = ftrace_find_rec_direct(ip);
2599+
#else
2600+
addr = READ_ONCE(ops->direct_call);
2601+
#endif
25972602
if (!addr)
25982603
return;
25992604

@@ -5986,6 +5991,10 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long ip, unsigned lo
59865991
if (!hash)
59875992
return -ENOMEM;
59885993

5994+
#ifndef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
5995+
ops->direct_call = addr;
5996+
#endif
5997+
59895998
err = register_ftrace_direct_hash(ops, hash);
59905999
free_ftrace_hash(hash);
59916000
return err;
@@ -6050,6 +6059,10 @@ int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long ip, unsigned long
60506059
return -ENOMEM;
60516060

60526061
err = modify_ftrace_direct_hash(ops, hash, lock_direct_mutex);
6062+
#ifndef CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS
6063+
if (!err)
6064+
ops->direct_call = addr;
6065+
#endif
60536066
free_ftrace_hash(hash);
60546067
return err;
60556068
}

0 commit comments

Comments
 (0)