mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
trampoline_count fills all trampoline attachment slots for a single
target function and verifies that one extra attach fails with -E2BIG.
It currently targets bpf_modify_return_test, which is also used by
other selftests such as modify_return, get_func_ip_test, and
get_func_args_test. When such tests run in parallel, they can contend
for the same per-function trampoline quota and cause unexpected attach
failures. This issue is currently masked by harness serialization.
Move trampoline_count to a dedicated bpf_testmod target and register it
for fmod_ret attachment. Also route the final trigger through
trigger_module_test_read(), so the execution path exercises the same
dedicated target.
This keeps the test semantics unchanged while isolating it from other
selftests, so it no longer needs to run in serial mode. Remove the
TODO comment as well.
Tested:
./test_progs -t trampoline_count -vv
./test_progs -j$(nproc) -t trampoline_count -vv
./test_progs -j$(nproc) -t \
trampoline_count,modify_return,get_func_ip_test,get_func_args_test -vv
20 runs of:
./test_progs -j$(nproc) -t \
trampoline_count,modify_return,get_func_ip_test,get_func_args_test
Signed-off-by: Sun Jian <sun.jian.kdev@gmail.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20260324044949.869801-1-sun.jian.kdev@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
90 lines
2.0 KiB
C
90 lines
2.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
#define _GNU_SOURCE
|
|
#include <test_progs.h>
|
|
|
|
struct inst {
|
|
struct bpf_object *obj;
|
|
struct bpf_link *link;
|
|
};
|
|
|
|
static struct bpf_program *load_prog(char *file, char *name, struct inst *inst)
|
|
{
|
|
struct bpf_object *obj;
|
|
struct bpf_program *prog;
|
|
int err;
|
|
|
|
obj = bpf_object__open_file(file, NULL);
|
|
if (!ASSERT_OK_PTR(obj, "obj_open_file"))
|
|
return NULL;
|
|
|
|
inst->obj = obj;
|
|
|
|
err = bpf_object__load(obj);
|
|
if (!ASSERT_OK(err, "obj_load"))
|
|
return NULL;
|
|
|
|
prog = bpf_object__find_program_by_name(obj, name);
|
|
if (!ASSERT_OK_PTR(prog, "obj_find_prog"))
|
|
return NULL;
|
|
|
|
return prog;
|
|
}
|
|
|
|
void test_trampoline_count(void)
|
|
{
|
|
char *file = "test_trampoline_count.bpf.o";
|
|
char *const progs[] = { "fentry_test", "fmod_ret_test", "fexit_test" };
|
|
int bpf_max_tramp_links, i;
|
|
struct bpf_program *prog;
|
|
struct bpf_link *link;
|
|
struct inst *inst;
|
|
|
|
bpf_max_tramp_links = get_bpf_max_tramp_links();
|
|
if (!ASSERT_GE(bpf_max_tramp_links, 1, "bpf_max_tramp_links"))
|
|
return;
|
|
inst = calloc(bpf_max_tramp_links + 1, sizeof(*inst));
|
|
if (!ASSERT_OK_PTR(inst, "inst"))
|
|
return;
|
|
|
|
/* attach 'allowed' trampoline programs */
|
|
for (i = 0; i < bpf_max_tramp_links; i++) {
|
|
prog = load_prog(file, progs[i % ARRAY_SIZE(progs)], &inst[i]);
|
|
if (!prog)
|
|
goto cleanup;
|
|
|
|
link = bpf_program__attach(prog);
|
|
if (!ASSERT_OK_PTR(link, "attach_prog"))
|
|
goto cleanup;
|
|
|
|
inst[i].link = link;
|
|
}
|
|
|
|
/* and try 1 extra.. */
|
|
prog = load_prog(file, "fmod_ret_test", &inst[i]);
|
|
if (!prog)
|
|
goto cleanup;
|
|
|
|
/* ..that needs to fail */
|
|
link = bpf_program__attach(prog);
|
|
if (!ASSERT_ERR_PTR(link, "attach_prog")) {
|
|
inst[i].link = link;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* with E2BIG error */
|
|
if (!ASSERT_EQ(libbpf_get_error(link), -E2BIG, "E2BIG"))
|
|
goto cleanup;
|
|
if (!ASSERT_EQ(link, NULL, "ptr_is_null"))
|
|
goto cleanup;
|
|
|
|
/* and finally execute the probe */
|
|
ASSERT_OK(trigger_module_test_read(256), "trigger_module_test_read");
|
|
|
|
cleanup:
|
|
for (; i >= 0; i--) {
|
|
bpf_link__destroy(inst[i].link);
|
|
bpf_object__close(inst[i].obj);
|
|
}
|
|
free(inst);
|
|
}
|