Re: [PATCH bpf-next v2] selftests/bpf: Wait for wq callback before checking ok_sleepable

From: Alexei Starovoitov

Date: Mon Nov 02 2026 - 01:17:45 EST


On Sun, Nov 01, 2026 at 06:36 PM Jonathan Bastari Thamrin via B4 Relay <devnull+thamrinjonathan.gmail.com@xxxxxxxxxx> wrote:
> ASSERT_OK(err, "test_run");
> ASSERT_EQ(topts.retval, 0, "test_run");
>
> - usleep(50); /* 10 usecs should be enough, but give it extra */
> -
> + /* wait for wq callback to finish */
> + while (!READ_ONCE(wq_skel->bss->wq_cb_run))
> + sched_yield();

This loop can spin forever.
The two ASSERTs above it don't stop the test. When retval != 0 nothing
starts the wq and wq_cb_run stays 0.

what goes wrong today with the patch
------------------------------- ------ --------------
test_run fails or retval != 0 FAIL hang
the callback doesn't run FAIL hang
the callback gets a wrong key FAIL FAIL

The second row is what this test is for.
The watchdog doesn't help. watchdog_timer_func() sends one SIGSEGV.
crash_handler() prints the stack and returns. The loop goes on.

Waiting for the callback is right. Waiting forever is not.
Keep the loop bounded, like prog_tests/ksock_wq.c.
Then there is no need for wq_cb_run and for the changes in progs/wq.c.

Something like this (not even compile tested):

diff --git a/tools/testing/selftests/bpf/prog_tests/wq.c b/tools/testing/selftests/bpf/prog_tests/wq.c
index 97926e3..c4de70b 100644
--- a/tools/testing/selftests/bpf/prog_tests/wq.c
+++ b/tools/testing/selftests/bpf/prog_tests/wq.c
@@ -7,7 +7,7 @@
void serial_test_wq(void)
{
struct wq *wq_skel = NULL;
- int err, prog_fd;
+ int err, prog_fd, i;

LIBBPF_OPTS(bpf_test_run_opts, topts);

@@ -25,11 +25,13 @@ void serial_test_wq(void)

prog_fd = bpf_program__fd(wq_skel->progs.test_syscall_array_sleepable);
err = bpf_prog_test_run_opts(prog_fd, &topts);
- ASSERT_OK(err, "test_run");
- ASSERT_EQ(topts.retval, 0, "test_run");
-
- usleep(50); /* 10 usecs should be enough, but give it extra */
+ if (!ASSERT_OK(err, "test_run") ||
+ !ASSERT_EQ(topts.retval, 0, "test_run"))
+ goto clean_up;

+ /* The callback runs in a kworker. Fail instead of a hang if it doesn't. */
+ for (i = 0; i < 10000 && !READ_ONCE(wq_skel->bss->ok_sleepable); i++)
+ usleep(1000);
ASSERT_EQ(wq_skel->bss->ok_sleepable, (1 << 1), "ok_sleepable");
clean_up:
wq__destroy(wq_skel);

pw-bot: cr