mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
Add a new selftest suite `exe_ctx` to verify the accuracy of the bpf_in_task(), bpf_in_hardirq(), and bpf_in_serving_softirq() helpers introduced in bpf_experimental.h. Testing these execution contexts deterministically requires crossing context boundaries within a single CPU. To achieve this, the test implements a "Trigger-Observer" pattern using bpf_testmod: 1. Trigger: A BPF syscall program calls a new bpf_testmod kfunc bpf_kfunc_trigger_ctx_check(). 2. Task to HardIRQ: The kfunc uses irq_work_queue() to trigger a self-IPI on the local CPU. 3. HardIRQ to SoftIRQ: The irq_work handler calls a dummy function (observed by BPF fentry) and then schedules a tasklet to transition into SoftIRQ context. The user-space runner ensures determinism by pinning itself to CPU 0 before execution, forcing the entire interrupt chain to remain on a single core. Dummy noinline functions with compiler barriers are added to bpf_testmod.c to serve as stable attachment points for fentry programs. A retry loop is used in user-space to wait for the asynchronous SoftIRQ to complete. Note that testing on s390x is avoided because supporting those helpers purely in BPF on s390x is not possible at this point. Reviewed-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Changwoo Min <changwoo@igalia.com> Link: https://lore.kernel.org/r/20260125115413.117502-3-changwoo@igalia.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
60 lines
1.6 KiB
C
60 lines
1.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2026 Valve Corporation.
|
|
* Author: Changwoo Min <changwoo@igalia.com>
|
|
*/
|
|
|
|
#include <test_progs.h>
|
|
#include <sys/syscall.h>
|
|
#include "test_ctx.skel.h"
|
|
|
|
void test_exe_ctx(void)
|
|
{
|
|
LIBBPF_OPTS(bpf_test_run_opts, opts);
|
|
cpu_set_t old_cpuset, target_cpuset;
|
|
struct test_ctx *skel;
|
|
int err, prog_fd;
|
|
|
|
/* 1. Pin the current process to CPU 0. */
|
|
if (sched_getaffinity(0, sizeof(old_cpuset), &old_cpuset) == 0) {
|
|
CPU_ZERO(&target_cpuset);
|
|
CPU_SET(0, &target_cpuset);
|
|
ASSERT_OK(sched_setaffinity(0, sizeof(target_cpuset),
|
|
&target_cpuset), "setaffinity");
|
|
}
|
|
|
|
skel = test_ctx__open_and_load();
|
|
if (!ASSERT_OK_PTR(skel, "skel_load"))
|
|
goto restore_affinity;
|
|
|
|
err = test_ctx__attach(skel);
|
|
if (!ASSERT_OK(err, "skel_attach"))
|
|
goto cleanup;
|
|
|
|
/* 2. When we run this, the kernel will execute the BPF prog on CPU 0. */
|
|
prog_fd = bpf_program__fd(skel->progs.trigger_all_contexts);
|
|
err = bpf_prog_test_run_opts(prog_fd, &opts);
|
|
ASSERT_OK(err, "test_run_trigger");
|
|
|
|
/* 3. Wait for the local CPU's softirq/tasklet to finish. */
|
|
for (int i = 0; i < 1000; i++) {
|
|
if (skel->bss->count_task > 0 &&
|
|
skel->bss->count_hardirq > 0 &&
|
|
skel->bss->count_softirq > 0)
|
|
break;
|
|
usleep(1000); /* Wait 1ms per iteration, up to 1 sec total */
|
|
}
|
|
|
|
/* On CPU 0, these should now all be non-zero. */
|
|
ASSERT_GT(skel->bss->count_task, 0, "task_ok");
|
|
ASSERT_GT(skel->bss->count_hardirq, 0, "hardirq_ok");
|
|
ASSERT_GT(skel->bss->count_softirq, 0, "softirq_ok");
|
|
|
|
cleanup:
|
|
test_ctx__destroy(skel);
|
|
|
|
restore_affinity:
|
|
ASSERT_OK(sched_setaffinity(0, sizeof(old_cpuset), &old_cpuset),
|
|
"restore_affinity");
|
|
}
|