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