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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.