169 lines · c
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 else73 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, which115 * should cause attach to fail due to us setting the hotplug seq above116 */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_TEST152 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)169