From: Tao Cui <cui.tao@linux.dev>
To: Tejun Heo <tj@kernel.org>
Cc: David Vernet <void@manifault.com>,
Andrea Righi <arighi@nvidia.com>,
Changwoo Min <changwoo@igalia.com>,
sched-ext@lists.linux.dev, Tao Cui <cuitao@kylinos.cn>,
cui.tao@linux.dev
Subject: [PATCH v2 3/6] selftests/sched_ext: Fail loudly when EXIT_KIND is missing from BTF
Date: Wed, 14 Oct 2026 21:13:22 +0800 [thread overview]
Message-ID: <20261014131325.793640-4-cui.tao@linux.dev> (raw)
In-Reply-To: <20261014131325.793640-1-cui.tao@linux.dev>
From: Tao Cui <cuitao@kylinos.cn>
EXIT_KIND() resolved scx_exit_kind values through
__COMPAT_ENUM_OR_ZERO(), which maps a missing enumerator to 0 (==
SCX_EXIT_NONE). struct scx_exit_info carries the enum itself, so the
BTF of any loaded scheduler always has the type, and every enumerator
the tests resolve today exists on all sched_ext kernels: the fallback
got the value right, and the single comparison that could pass
vacuously was the kick.c error poll.
Still, a silently-zeroed lookup is a trap. EXIT_KIND() is now an
alias of SCX_KIND_VAL(), which fails the test loudly when the
enumerator is missing. Convert the remaining
`kind != EXIT_KIND(SCX_EXIT_NONE)` checks (allowed_cpus,
cgroup_nr_cpus, cyclic_kick_wait and enq_blocked) to UEI_EXITED() so
they keep their semantics without a BTF lookup, and hoist kick.c
invalid_one()'s error_kind resolution above the gated-worker spawn so
a failing lookup cannot bypass its cleanup path. The <unistd.h>
include that the v1 posting added is not needed here; compat.h
already pulls it in.
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
.../selftests/sched_ext/allowed_cpus.c | 2 +-
.../selftests/sched_ext/cgroup_nr_cpus.c | 2 +-
.../selftests/sched_ext/cyclic_kick_wait.c | 2 +-
.../testing/selftests/sched_ext/enq_blocked.c | 2 +-
tools/testing/selftests/sched_ext/kick.c | 8 ++++---
tools/testing/selftests/sched_ext/nohz_tick.c | 6 ++---
tools/testing/selftests/sched_ext/scx_test.h | 22 ++++++++++++++-----
7 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/tools/testing/selftests/sched_ext/allowed_cpus.c b/tools/testing/selftests/sched_ext/allowed_cpus.c
index 773699d120ea..76311728a6b1 100644
--- a/tools/testing/selftests/sched_ext/allowed_cpus.c
+++ b/tools/testing/selftests/sched_ext/allowed_cpus.c
@@ -149,7 +149,7 @@ static enum scx_test_status run(void *ctx)
/* Just sleeping is fine, plenty of scheduling events happening. */
sleep(1);
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly");
goto out;
}
diff --git a/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c b/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c
index 4973f7080353..1475a8b3f05f 100644
--- a/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c
+++ b/tools/testing/selftests/sched_ext/cgroup_nr_cpus.c
@@ -400,7 +400,7 @@ static enum scx_test_status run(void *arg)
!wait_nr_cpus(&ctx, ctx.leaf, nr_child, "leaf after cpuset disable"))
goto out;
- if (ctx.skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(ctx.skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly");
goto out;
}
diff --git a/tools/testing/selftests/sched_ext/cyclic_kick_wait.c b/tools/testing/selftests/sched_ext/cyclic_kick_wait.c
index c2e5aa9de715..178d1d75f332 100644
--- a/tools/testing/selftests/sched_ext/cyclic_kick_wait.c
+++ b/tools/testing/selftests/sched_ext/cyclic_kick_wait.c
@@ -152,7 +152,7 @@ static enum scx_test_status run(void *ctx)
sleep(5);
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly (kind=%llu code=%lld)",
(unsigned long long)skel->data->uei.kind,
(long long)skel->data->uei.exit_code);
diff --git a/tools/testing/selftests/sched_ext/enq_blocked.c b/tools/testing/selftests/sched_ext/enq_blocked.c
index 26204548bbf0..1d5e090b54bc 100644
--- a/tools/testing/selftests/sched_ext/enq_blocked.c
+++ b/tools/testing/selftests/sched_ext/enq_blocked.c
@@ -844,7 +844,7 @@ static enum scx_test_status run_one(bool enq_blocked, bool cross_cpu,
}
}
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly (kind=%llu code=%lld)",
(unsigned long long)skel->data->uei.kind,
(long long)skel->data->uei.exit_code);
diff --git a/tools/testing/selftests/sched_ext/kick.c b/tools/testing/selftests/sched_ext/kick.c
index 7f01602c75b2..40c91d54c1eb 100644
--- a/tools/testing/selftests/sched_ext/kick.c
+++ b/tools/testing/selftests/sched_ext/kick.c
@@ -97,7 +97,7 @@ static bool wait_for_state(struct kick *skel, u32 wanted)
for (i = 0; i < WAIT_LOOPS; i++) {
if (__atomic_load_n(&skel->bss->state, __ATOMIC_ACQUIRE) == wanted)
return true;
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
usleep(1000);
}
@@ -111,7 +111,7 @@ static bool wait_for_counter(struct kick *skel, const u64 *counter, u64 wanted)
for (i = 0; i < WAIT_LOOPS; i++) {
if (__atomic_load_n(counter, __ATOMIC_ACQUIRE) >= wanted)
return true;
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
usleep(1000);
}
@@ -421,7 +421,9 @@ static enum scx_test_status invalid_one(struct kick_ctx *ctx, u32 scenario)
enum scx_test_status ret = SCX_TEST_FAIL;
int cpu = ctx->target_cpu;
int i;
+ u64 error_kind;
+ error_kind = EXIT_KIND(SCX_EXIT_ERROR);
victim = scx_test_spawn_gated_worker(cpu, false);
if (victim.pid < 0)
return SCX_TEST_FAIL;
@@ -440,7 +442,7 @@ static enum scx_test_status invalid_one(struct kick_ctx *ctx, u32 scenario)
goto out;
for (i = 0; i < WAIT_LOOPS; i++) {
- if (skel->data->uei.kind == EXIT_KIND(SCX_EXIT_ERROR)) {
+ if (UEI_EXITED(skel, uei) == error_kind) {
ret = SCX_TEST_PASS;
break;
}
diff --git a/tools/testing/selftests/sched_ext/nohz_tick.c b/tools/testing/selftests/sched_ext/nohz_tick.c
index df40976b9166..e19a97034b7f 100644
--- a/tools/testing/selftests/sched_ext/nohz_tick.c
+++ b/tools/testing/selftests/sched_ext/nohz_tick.c
@@ -165,7 +165,7 @@ static bool wait_for_counter(struct nohz_tick *skel, const u64 *counter, u64 val
for (elapsed = 0; elapsed < timeout_ms; elapsed++) {
if (__atomic_load_n(counter, __ATOMIC_RELAXED) >= value)
return true;
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
usleep(1000);
}
@@ -182,7 +182,7 @@ static bool wait_for_tick_stop(struct nohz_tick *skel, const u64 *counter, int t
u64 curr;
usleep(1000);
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE))
+ if (UEI_EXITED(skel, uei))
return false;
curr = __atomic_load_n(counter, __ATOMIC_RELAXED);
if (curr == prev) {
@@ -461,7 +461,7 @@ static enum scx_test_status run(void *ctx_ptr)
scx_test_stop_gated_worker(&challenger);
check_exit:
- if (skel->data->uei.kind != EXIT_KIND(SCX_EXIT_NONE)) {
+ if (UEI_EXITED(skel, uei)) {
SCX_ERR("Scheduler exited unexpectedly (kind=%llu code=%lld)",
(unsigned long long)skel->data->uei.kind,
(long long)skel->data->uei.exit_code);
diff --git a/tools/testing/selftests/sched_ext/scx_test.h b/tools/testing/selftests/sched_ext/scx_test.h
index 90b8d6915bb7..319e67f19b6d 100644
--- a/tools/testing/selftests/sched_ext/scx_test.h
+++ b/tools/testing/selftests/sched_ext/scx_test.h
@@ -18,8 +18,6 @@ enum scx_test_status {
SCX_TEST_FAIL,
};
-#define EXIT_KIND(__ent) __COMPAT_ENUM_OR_ZERO("scx_exit_kind", #__ent)
-
struct scx_test {
/**
* name - The name of the testcase.
@@ -119,13 +117,25 @@ void scx_test_register(struct scx_test *test);
(s64)__val; \
})
+/*
+ * SCX_KIND_VAL - Resolve an scx_exit_kind enumerator from kernel BTF.
+ *
+ * Unlike __COMPAT_ENUM_OR_ZERO(), a missing enumerator fails the test
+ * loudly instead of silently resolving to 0 (== SCX_EXIT_NONE), which
+ * would make the comparison vacuous.
+ */
#define SCX_KIND_VAL(__kind) ({ \
- u64 __val = 0; \
- bool __found = false; \
+ u64 __val = 0; \
\
- __found = __COMPAT_read_enum("scx_exit_kind", #__kind, &__val); \
- SCX_ASSERT(__found); \
+ if (!__COMPAT_read_enum("scx_exit_kind", #__kind, &__val)) \
+ SCX_FAIL("scx_exit_kind.%s not found in kernel BTF", #__kind); \
__val; \
})
+/*
+ * EXIT_KIND - Alias of SCX_KIND_VAL() for resolving scx_exit_kind
+ * enumerator values, kept for readability at the EXIT_KIND() call sites.
+ */
+#define EXIT_KIND(__ent) SCX_KIND_VAL(__ent)
+
#endif // # __SCX_TEST_H__
--
2.53.0
next prev parent reply other threads:[~2026-10-14 13:13 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-14 13:13 [PATCH v2 0/6] sched_ext: selftest infrastructure fixes Tao Cui
2026-10-14 13:13 ` [PATCH v2 1/6] selftests/sched_ext: Fix reload_loop error-path use-after-free Tao Cui
2026-10-14 13:13 ` [PATCH v2 2/6] sched_ext: Add SCX_ECODE_RSN_CGROUP_OFFLINE to user_exit_info.h Tao Cui
2026-10-14 13:13 ` Tao Cui [this message]
2026-10-14 13:28 ` [PATCH v2 3/6] selftests/sched_ext: Fail loudly when EXIT_KIND is missing from BTF sashiko-bot
2026-10-14 13:13 ` [PATCH v2 4/6] selftests/sched_ext: Add SCX_ASSERT_ALIVE and adopt it Tao Cui
2026-10-14 13:13 ` [PATCH v2 5/6] selftests/sched_ext: Bound exit waits Tao Cui
2026-10-14 13:13 ` [PATCH v2 6/6] selftests/sched_ext: Report reload_loop attach failures Tao Cui
2026-10-14 13:24 ` sashiko-bot
2026-10-14 18:29 ` [PATCH v2 0/6] sched_ext: selftest infrastructure fixes Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261014131325.793640-4-cui.tao@linux.dev \
--to=cui.tao@linux.dev \
--cc=arighi@nvidia.com \
--cc=changwoo@igalia.com \
--cc=cuitao@kylinos.cn \
--cc=sched-ext@lists.linux.dev \
--cc=tj@kernel.org \
--cc=void@manifault.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox