mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
Merge branch 'bpf-tail-calls-in-sleepable-programs'
Jiri Olsa says: ==================== this patchset allows sleepable programs to use tail calls. At the moment we need to have separate sleepable uprobe program to retrieve user space data and pass it to complex program with tail calls. It'd be great if the program with tail calls could be sleepable and do the data retrieval directly. ==================== Link: https://patch.msgid.link/20260130081208.1130204-1-jolsa@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
b18a761ca0
|
|
@ -287,6 +287,7 @@ struct bpf_map_owner {
|
|||
enum bpf_prog_type type;
|
||||
bool jited;
|
||||
bool xdp_has_frags;
|
||||
bool sleepable;
|
||||
u64 storage_cookie[MAX_BPF_CGROUP_STORAGE_TYPE];
|
||||
const struct btf_type *attach_func_proto;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
|
|
|
|||
|
|
@ -2401,6 +2401,7 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
|
|||
map->owner->type = prog_type;
|
||||
map->owner->jited = fp->jited;
|
||||
map->owner->xdp_has_frags = aux->xdp_has_frags;
|
||||
map->owner->sleepable = fp->sleepable;
|
||||
map->owner->expected_attach_type = fp->expected_attach_type;
|
||||
map->owner->attach_func_proto = aux->attach_func_proto;
|
||||
for_each_cgroup_storage_type(i) {
|
||||
|
|
@ -2412,7 +2413,8 @@ static bool __bpf_prog_map_compatible(struct bpf_map *map,
|
|||
} else {
|
||||
ret = map->owner->type == prog_type &&
|
||||
map->owner->jited == fp->jited &&
|
||||
map->owner->xdp_has_frags == aux->xdp_has_frags;
|
||||
map->owner->xdp_has_frags == aux->xdp_has_frags &&
|
||||
map->owner->sleepable == fp->sleepable;
|
||||
if (ret &&
|
||||
map->map_type == BPF_MAP_TYPE_PROG_ARRAY &&
|
||||
map->owner->expected_attach_type != fp->expected_attach_type)
|
||||
|
|
|
|||
|
|
@ -21386,6 +21386,7 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
|
|||
case BPF_MAP_TYPE_STACK:
|
||||
case BPF_MAP_TYPE_ARENA:
|
||||
case BPF_MAP_TYPE_INSN_ARRAY:
|
||||
case BPF_MAP_TYPE_PROG_ARRAY:
|
||||
break;
|
||||
default:
|
||||
verbose(env,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "tailcall_freplace.skel.h"
|
||||
#include "tc_bpf2bpf.skel.h"
|
||||
#include "tailcall_fail.skel.h"
|
||||
#include "tailcall_sleepable.skel.h"
|
||||
|
||||
/* test_tailcall_1 checks basic functionality by patching multiple locations
|
||||
* in a single program for a single tail call slot with nop->jmp, jmp->nop
|
||||
|
|
@ -1653,6 +1654,77 @@ static void test_tailcall_failure()
|
|||
RUN_TESTS(tailcall_fail);
|
||||
}
|
||||
|
||||
noinline void uprobe_sleepable_trigger(void)
|
||||
{
|
||||
asm volatile ("");
|
||||
}
|
||||
|
||||
static void test_tailcall_sleepable(void)
|
||||
{
|
||||
LIBBPF_OPTS(bpf_uprobe_opts, opts);
|
||||
struct tailcall_sleepable *skel;
|
||||
int prog_fd, map_fd;
|
||||
int err, key;
|
||||
|
||||
skel = tailcall_sleepable__open();
|
||||
if (!ASSERT_OK_PTR(skel, "tailcall_sleepable__open"))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Test that we can't load uprobe_normal and uprobe_sleepable_1,
|
||||
* because they share tailcall map.
|
||||
*/
|
||||
bpf_program__set_autoload(skel->progs.uprobe_normal, true);
|
||||
bpf_program__set_autoload(skel->progs.uprobe_sleepable_1, true);
|
||||
|
||||
err = tailcall_sleepable__load(skel);
|
||||
if (!ASSERT_ERR(err, "tailcall_sleepable__load"))
|
||||
goto out;
|
||||
|
||||
tailcall_sleepable__destroy(skel);
|
||||
|
||||
/*
|
||||
* Test that we can tail call from sleepable to sleepable program.
|
||||
*/
|
||||
skel = tailcall_sleepable__open();
|
||||
if (!ASSERT_OK_PTR(skel, "tailcall_sleepable__open"))
|
||||
return;
|
||||
|
||||
bpf_program__set_autoload(skel->progs.uprobe_sleepable_1, true);
|
||||
bpf_program__set_autoload(skel->progs.uprobe_sleepable_2, true);
|
||||
|
||||
err = tailcall_sleepable__load(skel);
|
||||
if (!ASSERT_OK(err, "tailcall_sleepable__load"))
|
||||
goto out;
|
||||
|
||||
/* Add sleepable uprobe_sleepable_2 to jmp_table[0]. */
|
||||
key = 0;
|
||||
prog_fd = bpf_program__fd(skel->progs.uprobe_sleepable_2);
|
||||
map_fd = bpf_map__fd(skel->maps.jmp_table);
|
||||
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
|
||||
if (!ASSERT_OK(err, "update jmp_table"))
|
||||
goto out;
|
||||
|
||||
skel->bss->my_pid = getpid();
|
||||
|
||||
/* Attach uprobe_sleepable_1 to uprobe_sleepable_trigger and hit it. */
|
||||
opts.func_name = "uprobe_sleepable_trigger";
|
||||
skel->links.uprobe_sleepable_1 = bpf_program__attach_uprobe_opts(
|
||||
skel->progs.uprobe_sleepable_1,
|
||||
-1,
|
||||
"/proc/self/exe",
|
||||
0 /* offset */,
|
||||
&opts);
|
||||
if (!ASSERT_OK_PTR(skel->links.uprobe_sleepable_1, "bpf_program__attach_uprobe_opts"))
|
||||
goto out;
|
||||
|
||||
uprobe_sleepable_trigger();
|
||||
ASSERT_EQ(skel->bss->executed, 1, "executed");
|
||||
|
||||
out:
|
||||
tailcall_sleepable__destroy(skel);
|
||||
}
|
||||
|
||||
void test_tailcalls(void)
|
||||
{
|
||||
if (test__start_subtest("tailcall_1"))
|
||||
|
|
@ -1707,4 +1779,6 @@ void test_tailcalls(void)
|
|||
test_tailcall_bpf2bpf_freplace();
|
||||
if (test__start_subtest("tailcall_failure"))
|
||||
test_tailcall_failure();
|
||||
if (test__start_subtest("tailcall_sleepable"))
|
||||
test_tailcall_sleepable();
|
||||
}
|
||||
|
|
|
|||
43
tools/testing/selftests/bpf/progs/tailcall_sleepable.c
Normal file
43
tools/testing/selftests/bpf/progs/tailcall_sleepable.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf_misc.h"
|
||||
#include "bpf_test_utils.h"
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(key_size, sizeof(__u32));
|
||||
__array(values, void (void));
|
||||
} jmp_table SEC(".maps");
|
||||
|
||||
SEC("?uprobe")
|
||||
int uprobe_normal(void *ctx)
|
||||
{
|
||||
bpf_tail_call_static(ctx, &jmp_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?uprobe.s")
|
||||
int uprobe_sleepable_1(void *ctx)
|
||||
{
|
||||
bpf_tail_call_static(ctx, &jmp_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int executed = 0;
|
||||
int my_pid = 0;
|
||||
|
||||
SEC("?uprobe.s")
|
||||
int uprobe_sleepable_2(void *ctx)
|
||||
{
|
||||
int pid = bpf_get_current_pid_tgid() >> 32;
|
||||
|
||||
if (pid != my_pid)
|
||||
return 0;
|
||||
|
||||
executed++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
Loading…
Reference in New Issue
Block a user