187 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * Copyright (c) 2024 Meta Platforms, Inc. and affiliates.4 * Copyright (c) 2024 Tejun Heo <tj@kernel.org>5 * Copyright (c) 2024 David Vernet <dvernet@meta.com>6 */7#ifndef __SCX_COMPAT_H8#define __SCX_COMPAT_H9 10#include <bpf/btf.h>11#include <fcntl.h>12#include <stdlib.h>13#include <unistd.h>14 15struct btf *__COMPAT_vmlinux_btf __attribute__((weak));16 17static inline void __COMPAT_load_vmlinux_btf(void)18{19 if (!__COMPAT_vmlinux_btf) {20 __COMPAT_vmlinux_btf = btf__load_vmlinux_btf();21 SCX_BUG_ON(!__COMPAT_vmlinux_btf, "btf__load_vmlinux_btf()");22 }23}24 25static inline bool __COMPAT_read_enum(const char *type, const char *name, u64 *v)26{27 const struct btf_type *t;28 const char *n;29 s32 tid;30 int i;31 32 __COMPAT_load_vmlinux_btf();33 34 tid = btf__find_by_name(__COMPAT_vmlinux_btf, type);35 if (tid < 0)36 return false;37 38 t = btf__type_by_id(__COMPAT_vmlinux_btf, tid);39 SCX_BUG_ON(!t, "btf__type_by_id(%d)", tid);40 41 if (btf_is_enum(t)) {42 struct btf_enum *e = btf_enum(t);43 44 for (i = 0; i < BTF_INFO_VLEN(t->info); i++) {45 n = btf__name_by_offset(__COMPAT_vmlinux_btf, e[i].name_off);46 SCX_BUG_ON(!n, "btf__name_by_offset()");47 if (!strcmp(n, name)) {48 *v = e[i].val;49 return true;50 }51 }52 } else if (btf_is_enum64(t)) {53 struct btf_enum64 *e = btf_enum64(t);54 55 for (i = 0; i < BTF_INFO_VLEN(t->info); i++) {56 n = btf__name_by_offset(__COMPAT_vmlinux_btf, e[i].name_off);57 SCX_BUG_ON(!n, "btf__name_by_offset()");58 if (!strcmp(n, name)) {59 *v = btf_enum64_value(&e[i]);60 return true;61 }62 }63 }64 65 return false;66}67 68#define __COMPAT_ENUM_OR_ZERO(__type, __ent) \69({ \70 u64 __val = 0; \71 __COMPAT_read_enum(__type, __ent, &__val); \72 __val; \73})74 75static inline bool __COMPAT_has_ksym(const char *ksym)76{77 __COMPAT_load_vmlinux_btf();78 return btf__find_by_name(__COMPAT_vmlinux_btf, ksym) >= 0;79}80 81static inline bool __COMPAT_struct_has_field(const char *type, const char *field)82{83 const struct btf_type *t;84 const struct btf_member *m;85 const char *n;86 s32 tid;87 int i;88 89 __COMPAT_load_vmlinux_btf();90 tid = btf__find_by_name_kind(__COMPAT_vmlinux_btf, type, BTF_KIND_STRUCT);91 if (tid < 0)92 return false;93 94 t = btf__type_by_id(__COMPAT_vmlinux_btf, tid);95 SCX_BUG_ON(!t, "btf__type_by_id(%d)", tid);96 97 m = btf_members(t);98 99 for (i = 0; i < BTF_INFO_VLEN(t->info); i++) {100 n = btf__name_by_offset(__COMPAT_vmlinux_btf, m[i].name_off);101 SCX_BUG_ON(!n, "btf__name_by_offset()");102 if (!strcmp(n, field))103 return true;104 }105 106 return false;107}108 109#define SCX_OPS_SWITCH_PARTIAL \110 __COMPAT_ENUM_OR_ZERO("scx_ops_flags", "SCX_OPS_SWITCH_PARTIAL")111 112static inline long scx_hotplug_seq(void)113{114 int fd;115 char buf[32];116 ssize_t len;117 long val;118 119 fd = open("/sys/kernel/sched_ext/hotplug_seq", O_RDONLY);120 if (fd < 0)121 return -ENOENT;122 123 len = read(fd, buf, sizeof(buf) - 1);124 SCX_BUG_ON(len <= 0, "read failed (%ld)", len);125 buf[len] = 0;126 close(fd);127 128 val = strtoul(buf, NULL, 10);129 SCX_BUG_ON(val < 0, "invalid num hotplug events: %lu", val);130 131 return val;132}133 134/*135 * struct sched_ext_ops can change over time. If compat.bpf.h::SCX_OPS_DEFINE()136 * is used to define ops and compat.h::SCX_OPS_LOAD/ATTACH() are used to load137 * and attach it, backward compatibility is automatically maintained where138 * reasonable.139 *140 * ec7e3b0463e1 ("implement-ops") in https://github.com/sched-ext/sched_ext is141 * the current minimum required kernel version.142 */143#define SCX_OPS_OPEN(__ops_name, __scx_name) ({ \144 struct __scx_name *__skel; \145 \146 SCX_BUG_ON(!__COMPAT_struct_has_field("sched_ext_ops", "dump"), \147 "sched_ext_ops.dump() missing, kernel too old?"); \148 \149 __skel = __scx_name##__open(); \150 SCX_BUG_ON(!__skel, "Could not open " #__scx_name); \151 __skel->struct_ops.__ops_name->hotplug_seq = scx_hotplug_seq(); \152 __skel; \153})154 155#define SCX_OPS_LOAD(__skel, __ops_name, __scx_name, __uei_name) ({ \156 UEI_SET_SIZE(__skel, __ops_name, __uei_name); \157 SCX_BUG_ON(__scx_name##__load((__skel)), "Failed to load skel"); \158})159 160/*161 * New versions of bpftool now emit additional link placeholders for BPF maps,162 * and set up BPF skeleton in such a way that libbpf will auto-attach BPF maps163 * automatically, assumming libbpf is recent enough (v1.5+). Old libbpf will do164 * nothing with those links and won't attempt to auto-attach maps.165 *166 * To maintain compatibility with older libbpf while avoiding trying to attach167 * twice, disable the autoattach feature on newer libbpf.168 */169#if LIBBPF_MAJOR_VERSION > 1 || \170 (LIBBPF_MAJOR_VERSION == 1 && LIBBPF_MINOR_VERSION >= 5)171#define __SCX_OPS_DISABLE_AUTOATTACH(__skel, __ops_name) \172 bpf_map__set_autoattach((__skel)->maps.__ops_name, false)173#else174#define __SCX_OPS_DISABLE_AUTOATTACH(__skel, __ops_name) do {} while (0)175#endif176 177#define SCX_OPS_ATTACH(__skel, __ops_name, __scx_name) ({ \178 struct bpf_link *__link; \179 __SCX_OPS_DISABLE_AUTOATTACH(__skel, __ops_name); \180 SCX_BUG_ON(__scx_name##__attach((__skel)), "Failed to attach skel"); \181 __link = bpf_map__attach_struct_ops((__skel)->maps.__ops_name); \182 SCX_BUG_ON(!__link, "Failed to attach struct_ops"); \183 __link; \184})185 186#endif /* __SCX_COMPAT_H */187