mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
The module_attach test contains subtests which check that unloading a
module while there are BPF programs attached to its functions is not
possible because the module is still referenced.
The problem is that the test calls the generic unload_module() helper
function which is used for module cleanup after test_progs terminate and
tries to wait until all module references are released. This
unnecessarily slows down the module_attach subtests since each
unsuccessful call to unload_module() takes about 1 second.
Introduce try_unload_module() which takes the number of retries as a
parameter. Make unload_module() call it with the currently used amount
of 10000 retries but call it with just 1 retry from module_attach tests
as it is always expected to fail. This speeds up the module_attach()
test significantly.
Before:
# time ./test_progs -t module_attach
[...]
Summary: 1/14 PASSED, 0 SKIPPED, 0 FAILED
real 0m5.011s
user 0m0.293s
sys 0m0.108s
After:
# time ./test_progs -t module_attach
[...]
Summary: 1/14 PASSED, 0 SKIPPED, 0 FAILED
real 0m0.350s
user 0m0.197s
sys 0m0.063s
Signed-off-by: Viktor Malik <vmalik@redhat.com>
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260306101628.3822284-1-vmalik@redhat.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
195 lines
4.9 KiB
C
195 lines
4.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2020 Facebook */
|
|
|
|
#include <test_progs.h>
|
|
#include <stdbool.h>
|
|
#include "test_module_attach.skel.h"
|
|
#include "testing_helpers.h"
|
|
|
|
static const char * const read_tests[] = {
|
|
"handle_raw_tp",
|
|
"handle_tp_btf",
|
|
"handle_fentry",
|
|
"handle_fentry_explicit",
|
|
"handle_fmod_ret",
|
|
};
|
|
|
|
static const char * const detach_tests[] = {
|
|
"handle_fentry",
|
|
"handle_fexit",
|
|
"kprobe_multi",
|
|
};
|
|
|
|
static const int READ_SZ = 456;
|
|
static const int WRITE_SZ = 457;
|
|
|
|
static int trigger_module_test_writable(int *val)
|
|
{
|
|
int fd, err;
|
|
char buf[65];
|
|
ssize_t rd;
|
|
|
|
fd = open(BPF_TESTMOD_TEST_FILE, O_RDONLY);
|
|
err = -errno;
|
|
if (!ASSERT_GE(fd, 0, "testmode_file_open"))
|
|
return err;
|
|
|
|
rd = read(fd, buf, sizeof(buf) - 1);
|
|
err = -errno;
|
|
if (!ASSERT_GT(rd, 0, "testmod_file_rd_val")) {
|
|
close(fd);
|
|
return err;
|
|
}
|
|
|
|
buf[rd] = '\0';
|
|
*val = strtol(buf, NULL, 0);
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void test_module_attach_prog(const char *prog_name, int sz,
|
|
const char *attach_target, int ret)
|
|
{
|
|
struct test_module_attach *skel;
|
|
struct bpf_program *prog;
|
|
int err;
|
|
|
|
skel = test_module_attach__open();
|
|
if (!ASSERT_OK_PTR(skel, "module_attach open"))
|
|
return;
|
|
|
|
prog = bpf_object__find_program_by_name(skel->obj, prog_name);
|
|
if (!ASSERT_OK_PTR(prog, "module_attach find_program"))
|
|
goto cleanup;
|
|
bpf_program__set_autoload(prog, true);
|
|
|
|
if (attach_target) {
|
|
err = bpf_program__set_attach_target(prog, 0, attach_target);
|
|
if (!ASSERT_OK(err, attach_target))
|
|
goto cleanup;
|
|
}
|
|
|
|
err = test_module_attach__load(skel);
|
|
if (!ASSERT_OK(err, "module_attach load"))
|
|
goto cleanup;
|
|
|
|
err = test_module_attach__attach(skel);
|
|
if (!ASSERT_OK(err, "module_attach attach"))
|
|
goto cleanup;
|
|
|
|
if (sz) {
|
|
/* trigger both read and write though each test uses only one */
|
|
ASSERT_OK(trigger_module_test_read(sz), "trigger_read");
|
|
ASSERT_OK(trigger_module_test_write(sz), "trigger_write");
|
|
|
|
ASSERT_EQ(skel->bss->sz, sz, prog_name);
|
|
}
|
|
|
|
if (ret)
|
|
ASSERT_EQ(skel->bss->retval, ret, "ret");
|
|
cleanup:
|
|
test_module_attach__destroy(skel);
|
|
}
|
|
|
|
static void test_module_attach_writable(void)
|
|
{
|
|
struct test_module_attach__bss *bss;
|
|
struct test_module_attach *skel;
|
|
int writable_val = 0;
|
|
int err;
|
|
|
|
skel = test_module_attach__open();
|
|
if (!ASSERT_OK_PTR(skel, "module_attach open"))
|
|
return;
|
|
|
|
bpf_program__set_autoload(skel->progs.handle_raw_tp_writable_bare, true);
|
|
|
|
err = test_module_attach__load(skel);
|
|
if (!ASSERT_OK(err, "module_attach load"))
|
|
goto cleanup;
|
|
|
|
bss = skel->bss;
|
|
|
|
err = test_module_attach__attach(skel);
|
|
if (!ASSERT_OK(err, "module_attach attach"))
|
|
goto cleanup;
|
|
|
|
bss->raw_tp_writable_bare_early_ret = true;
|
|
bss->raw_tp_writable_bare_out_val = 0xf1f2f3f4;
|
|
ASSERT_OK(trigger_module_test_writable(&writable_val),
|
|
"trigger_writable");
|
|
ASSERT_EQ(bss->raw_tp_writable_bare_in_val, 1024, "writable_test_in");
|
|
ASSERT_EQ(bss->raw_tp_writable_bare_out_val, writable_val,
|
|
"writable_test_out");
|
|
cleanup:
|
|
test_module_attach__destroy(skel);
|
|
}
|
|
|
|
static void test_module_attach_detach(const char *prog_name)
|
|
{
|
|
struct test_module_attach *skel;
|
|
struct bpf_program *prog;
|
|
struct bpf_link *link;
|
|
int err;
|
|
|
|
skel = test_module_attach__open();
|
|
if (!ASSERT_OK_PTR(skel, "module_attach open"))
|
|
return;
|
|
|
|
prog = bpf_object__find_program_by_name(skel->obj, prog_name);
|
|
if (!ASSERT_OK_PTR(prog, "module_attach find_program"))
|
|
goto cleanup;
|
|
bpf_program__set_autoload(prog, true);
|
|
|
|
err = test_module_attach__load(skel);
|
|
if (!ASSERT_OK(err, "module_attach load"))
|
|
goto cleanup;
|
|
|
|
/* attach and make sure it gets module reference */
|
|
link = bpf_program__attach(prog);
|
|
if (!ASSERT_OK_PTR(link, "module_attach attach"))
|
|
goto cleanup;
|
|
|
|
ASSERT_ERR(try_unload_module("bpf_testmod", 1, false), "try_unload_module");
|
|
bpf_link__destroy(link);
|
|
cleanup:
|
|
test_module_attach__destroy(skel);
|
|
}
|
|
|
|
void test_module_attach(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(read_tests); i++) {
|
|
if (!test__start_subtest(read_tests[i]))
|
|
continue;
|
|
test_module_attach_prog(read_tests[i], READ_SZ, NULL, 0);
|
|
}
|
|
if (test__start_subtest("handle_raw_tp_bare"))
|
|
test_module_attach_prog("handle_raw_tp_bare", WRITE_SZ, NULL, 0);
|
|
if (test__start_subtest("handle_raw_tp_writable_bare"))
|
|
test_module_attach_writable();
|
|
if (test__start_subtest("handle_fentry_manual")) {
|
|
test_module_attach_prog("handle_fentry_manual", READ_SZ,
|
|
"bpf_testmod_test_read", 0);
|
|
}
|
|
if (test__start_subtest("handle_fentry_explicit_manual")) {
|
|
test_module_attach_prog("handle_fentry_explicit_manual",
|
|
READ_SZ,
|
|
"bpf_testmod:bpf_testmod_test_read", 0);
|
|
}
|
|
if (test__start_subtest("handle_fexit"))
|
|
test_module_attach_prog("handle_fexit", READ_SZ, NULL, -EIO);
|
|
if (test__start_subtest("handle_fexit_ret"))
|
|
test_module_attach_prog("handle_fexit_ret", 0, NULL, 0);
|
|
for (i = 0; i < ARRAY_SIZE(detach_tests); i++) {
|
|
char test_name[50];
|
|
|
|
snprintf(test_name, sizeof(test_name), "%s_detach", detach_tests[i]);
|
|
if (!test__start_subtest(test_name))
|
|
continue;
|
|
test_module_attach_detach(detach_tests[i]);
|
|
}
|
|
}
|