[PATCH] selftests/sched_ext: Handle CPU hotplug write failures
From: Tianyi Chen
Date: Sun Sep 06 2026 - 09:56:22 EST
toggle_online_status() logs failed CPU state changes but discards the
write result. The hotplug tests can consequently wait indefinitely for
a scheduler exit that the failed operation never triggered.
Return the write result and stop both hotplug tests when a required
CPU state change fails. Release the acquired scheduler resources on
these paths and let the existing cleanup callback retry restoring
CPU1. Also fail the test when its normal CPU restoration fails.
Tested in a two-vCPU VM running a kernel built from the same source
as the selftests. Injecting EIO with strace into each of the ten CPU
state writes makes the fixed test return 1, with CPU1 online and
sched_ext disabled after cleanup. The original test does not finish
within three seconds when either of the first two writes fails.
Normal hotplug tests pass before and after the change. Making the
online file read-only also produces a failure without hanging.
Fixes: a5db7817af78 ("sched_ext: Add selftests")
Assisted-by: LLM
Signed-off-by: Tianyi Chen <hi@xxxxxxxxx>
---
tools/testing/selftests/sched_ext/hotplug.c | 34 ++++++++++++++-------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/sched_ext/hotplug.c b/tools/testing/selftests/sched_ext/hotplug.c
index 0cfbb111a2d..10b8d42bd89 100644
--- a/tools/testing/selftests/sched_ext/hotplug.c
+++ b/tools/testing/selftests/sched_ext/hotplug.c
@@ -21,15 +21,17 @@ static bool is_cpu_online(void)
return file_read_long(online_path) > 0;
}
-static void toggle_online_status(bool online)
+static int toggle_online_status(bool online)
{
long val = online ? 1 : 0;
int ret;
ret = file_write_long(online_path, val);
if (ret != 0)
- fprintf(stderr, "Failed to bring CPU %s (%s)",
+ fprintf(stderr, "Failed to bring CPU %s (%s)\n",
online ? "online" : "offline", strerror(errno));
+
+ return ret;
}
static enum scx_test_status setup(void **ctx)
@@ -44,6 +46,7 @@ static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
{
struct hotplug *skel;
struct bpf_link *link;
+ enum scx_test_status status = SCX_TEST_FAIL;
long kind, code;
SCX_ASSERT(is_cpu_online());
@@ -54,8 +57,8 @@ static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
SCX_FAIL_IF(hotplug__load(skel), "Failed to load skel");
/* Testing the offline -> online path, so go offline before starting */
- if (onlining)
- toggle_online_status(0);
+ if (onlining && toggle_online_status(0))
+ goto out_destroy_skel;
if (cbs_defined) {
kind = SCX_KIND_VAL(SCX_EXIT_UNREG_BPF);
@@ -79,7 +82,8 @@ static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
return SCX_TEST_FAIL;
}
- toggle_online_status(onlining ? 1 : 0);
+ if (toggle_online_status(onlining ? 1 : 0))
+ goto out_destroy_link;
while (!UEI_EXITED(skel, uei))
sched_yield();
@@ -87,20 +91,23 @@ static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
SCX_EQ(skel->data->uei.kind, kind);
SCX_EQ(UEI_REPORT(skel, uei), code);
- if (!onlining)
- toggle_online_status(1);
+ if (!onlining && toggle_online_status(1))
+ goto out_destroy_link;
+ status = SCX_TEST_PASS;
+out_destroy_link:
bpf_link__destroy(link);
+out_destroy_skel:
hotplug__destroy(skel);
- return SCX_TEST_PASS;
+ return status;
}
static enum scx_test_status test_hotplug_attach(void)
{
struct hotplug *skel;
struct bpf_link *link;
- enum scx_test_status status = SCX_TEST_PASS;
+ enum scx_test_status status = SCX_TEST_FAIL;
long kind, code;
SCX_ASSERT(is_cpu_online());
@@ -115,10 +122,12 @@ static enum scx_test_status test_hotplug_attach(void)
* Take the CPU offline to increment the global hotplug seq, which
* should cause attach to fail due to us setting the hotplug seq above
*/
- toggle_online_status(0);
+ if (toggle_online_status(0))
+ goto out_destroy_skel;
link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
- toggle_online_status(1);
+ if (toggle_online_status(1))
+ goto out_destroy_link;
SCX_ASSERT(link);
while (!UEI_EXITED(skel, uei))
@@ -130,7 +139,10 @@ static enum scx_test_status test_hotplug_attach(void)
SCX_EQ(skel->data->uei.kind, kind);
SCX_EQ(UEI_REPORT(skel, uei), code);
+ status = SCX_TEST_PASS;
+out_destroy_link:
bpf_link__destroy(link);
+out_destroy_skel:
hotplug__destroy(skel);
return status;
--
2.55.0