Loading...
Note: File does not exist in v6.2.
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
4 * Copyright (c) 2024 David Vernet <dvernet@meta.com>
5 */
6#include <bpf/bpf.h>
7#include <sched.h>
8#include <scx/common.h>
9#include <sched.h>
10#include <sys/wait.h>
11#include <unistd.h>
12
13#include "hotplug_test.h"
14#include "hotplug.bpf.skel.h"
15#include "scx_test.h"
16#include "util.h"
17
18const char *online_path = "/sys/devices/system/cpu/cpu1/online";
19
20static bool is_cpu_online(void)
21{
22 return file_read_long(online_path) > 0;
23}
24
25static void toggle_online_status(bool online)
26{
27 long val = online ? 1 : 0;
28 int ret;
29
30 ret = file_write_long(online_path, val);
31 if (ret != 0)
32 fprintf(stderr, "Failed to bring CPU %s (%s)",
33 online ? "online" : "offline", strerror(errno));
34}
35
36static enum scx_test_status setup(void **ctx)
37{
38 if (!is_cpu_online())
39 return SCX_TEST_SKIP;
40
41 return SCX_TEST_PASS;
42}
43
44static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
45{
46 struct hotplug *skel;
47 struct bpf_link *link;
48 long kind, code;
49
50 SCX_ASSERT(is_cpu_online());
51
52 skel = hotplug__open_and_load();
53 SCX_ASSERT(skel);
54
55 /* Testing the offline -> online path, so go offline before starting */
56 if (onlining)
57 toggle_online_status(0);
58
59 if (cbs_defined) {
60 kind = SCX_KIND_VAL(SCX_EXIT_UNREG_BPF);
61 code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) | HOTPLUG_EXIT_RSN;
62 if (onlining)
63 code |= HOTPLUG_ONLINING;
64 } else {
65 kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
66 code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
67 SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
68 }
69
70 if (cbs_defined)
71 link = bpf_map__attach_struct_ops(skel->maps.hotplug_cb_ops);
72 else
73 link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
74
75 if (!link) {
76 SCX_ERR("Failed to attach scheduler");
77 hotplug__destroy(skel);
78 return SCX_TEST_FAIL;
79 }
80
81 toggle_online_status(onlining ? 1 : 0);
82
83 while (!UEI_EXITED(skel, uei))
84 sched_yield();
85
86 SCX_EQ(skel->data->uei.kind, kind);
87 SCX_EQ(UEI_REPORT(skel, uei), code);
88
89 if (!onlining)
90 toggle_online_status(1);
91
92 bpf_link__destroy(link);
93 hotplug__destroy(skel);
94
95 return SCX_TEST_PASS;
96}
97
98static enum scx_test_status test_hotplug_attach(void)
99{
100 struct hotplug *skel;
101 struct bpf_link *link;
102 enum scx_test_status status = SCX_TEST_PASS;
103 long kind, code;
104
105 SCX_ASSERT(is_cpu_online());
106 SCX_ASSERT(scx_hotplug_seq() > 0);
107
108 skel = SCX_OPS_OPEN(hotplug_nocb_ops, hotplug);
109 SCX_ASSERT(skel);
110
111 SCX_OPS_LOAD(skel, hotplug_nocb_ops, hotplug, uei);
112
113 /*
114 * Take the CPU offline to increment the global hotplug seq, which
115 * should cause attach to fail due to us setting the hotplug seq above
116 */
117 toggle_online_status(0);
118 link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
119
120 toggle_online_status(1);
121
122 SCX_ASSERT(link);
123 while (!UEI_EXITED(skel, uei))
124 sched_yield();
125
126 kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
127 code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
128 SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
129 SCX_EQ(skel->data->uei.kind, kind);
130 SCX_EQ(UEI_REPORT(skel, uei), code);
131
132 bpf_link__destroy(link);
133 hotplug__destroy(skel);
134
135 return status;
136}
137
138static enum scx_test_status run(void *ctx)
139{
140
141#define HP_TEST(__onlining, __cbs_defined) ({ \
142 if (test_hotplug(__onlining, __cbs_defined) != SCX_TEST_PASS) \
143 return SCX_TEST_FAIL; \
144})
145
146 HP_TEST(true, true);
147 HP_TEST(false, true);
148 HP_TEST(true, false);
149 HP_TEST(false, false);
150
151#undef HP_TEST
152
153 return test_hotplug_attach();
154}
155
156static void cleanup(void *ctx)
157{
158 toggle_online_status(1);
159}
160
161struct scx_test hotplug_test = {
162 .name = "hotplug",
163 .description = "Verify hotplug behavior",
164 .setup = setup,
165 .run = run,
166 .cleanup = cleanup,
167};
168REGISTER_SCX_TEST(&hotplug_test)