From: Tejun Heo <tj@kernel.org>
To: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>
Cc: Martin KaFai Lau <martin.lau@linux.dev>,
Emil Tsalapatis <emil@etsalapatis.com>,
David Vernet <void@manifault.com>,
Andrea Righi <arighi@nvidia.com>,
Changwoo Min <changwoo@igalia.com>,
bpf@vger.kernel.org, sched-ext@lists.linux.dev,
linux-kernel@vger.kernel.org, Tejun Heo <tj@kernel.org>
Subject: [PATCHSET SLOP RFC 6/6] sched_ext: Convert scx_bpf_cid_override() to take an arena pointer
Date: Sun, 12 Jul 2026 16:44:14 -1000 [thread overview]
Message-ID: <20260713024414.3759854-7-tj@kernel.org> (raw)
In-Reply-To: <20260713024414.3759854-1-tj@kernel.org>
The mem+size signature requires a verifier-visible buffer, which forces
scx_qmap to keep the cpu_to_cid array in writable bss even though nothing
writes it after load. Take the array as an __arena argument instead, with
the count passed in entries. The verifier hands the kfunc a
dereferenceable kernel address and nr_cpu_ids * sizeof(s32) stays within
the guard region covered by arena fault recovery, so the kfunc needs no
bounds check beyond the entry count validation.
scx_qmap moves the array into struct qmap_arena. As the arena is mmapped
at load, the loader now populates it between load and attach instead of
before load.
NOT_SIGNED_OFF: to be reworked after bpf-next is pulled into sched_ext
---
kernel/sched/ext/cid.c | 24 ++++++++++----
tools/sched_ext/include/scx/compat.bpf.h | 8 +++--
tools/sched_ext/scx_qmap.bpf.c | 13 ++------
tools/sched_ext/scx_qmap.c | 41 +++++++++++++++---------
tools/sched_ext/scx_qmap.h | 3 ++
5 files changed, 53 insertions(+), 36 deletions(-)
diff --git a/kernel/sched/ext/cid.c b/kernel/sched/ext/cid.c
index af83084ec740..872f699cb1ac 100644
--- a/kernel/sched/ext/cid.c
+++ b/kernel/sched/ext/cid.c
@@ -278,8 +278,8 @@ __bpf_kfunc_start_defs();
/**
* scx_bpf_cid_override - Install an explicit cpu->cid mapping
- * @cpu_to_cid: array of nr_cpu_ids s32 entries (cid for each cpu)
- * @cpu_to_cid__sz: must be nr_cpu_ids * sizeof(s32) bytes
+ * @cpu_to_cid__arena: arena array of nr_cpu_ids s32 entries (cid for each cpu)
+ * @cnt: number of entries, must be nr_cpu_ids
* @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
*
* May only be called from ops.init() of the root scheduler. Replace the
@@ -287,7 +287,7 @@ __bpf_kfunc_start_defs();
* must map to a unique cid in [0, num_possible_cpus()). Topo info is cleared.
* On invalid input, trigger scx_error() to abort the scheduler.
*/
-__bpf_kfunc void scx_bpf_cid_override(const s32 *cpu_to_cid, u32 cpu_to_cid__sz,
+__bpf_kfunc void scx_bpf_cid_override(const s32 *cpu_to_cid__arena, u32 cnt,
const struct bpf_prog_aux *aux)
{
cpumask_var_t seen __free(free_cpumask_var) = CPUMASK_VAR_NULL;
@@ -314,14 +314,24 @@ __bpf_kfunc void scx_bpf_cid_override(const s32 *cpu_to_cid, u32 cpu_to_cid__sz,
return;
}
- if (cpu_to_cid__sz != nr_cpu_ids * sizeof(s32)) {
- scx_error(sch, "scx_bpf_cid_override: expected %zu bytes, got %u",
- nr_cpu_ids * sizeof(s32), cpu_to_cid__sz);
+ if (!cpu_to_cid__arena) {
+ scx_error(sch, "scx_bpf_cid_override: NULL cpu_to_cid");
return;
}
+ if (cnt != nr_cpu_ids) {
+ scx_error(sch, "scx_bpf_cid_override: expected %u entries, got %u",
+ nr_cpu_ids, cnt);
+ return;
+ }
+
+ /*
+ * @cpu_to_cid__arena arrives rebased to the arena kernel mapping.
+ * nr_cpu_ids * sizeof(s32) stays within the guard region covered by
+ * arena fault recovery, so no explicit bounds check is needed.
+ */
for_each_possible_cpu(cpu) {
- s32 c = cpu_to_cid[cpu];
+ s32 c = cpu_to_cid__arena[cpu];
if (!cid_valid(sch, c))
return;
diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
index 87f15f296234..f71f843f9ddb 100644
--- a/tools/sched_ext/include/scx/compat.bpf.h
+++ b/tools/sched_ext/include/scx/compat.bpf.h
@@ -7,6 +7,8 @@
#ifndef __SCX_COMPAT_BPF_H
#define __SCX_COMPAT_BPF_H
+#include "bpf_arena_common.bpf.h"
+
#define __COMPAT_ENUM_OR_ZERO(__type, __ent) \
({ \
__type __ret = 0; \
@@ -125,12 +127,12 @@ static inline bool scx_bpf_sub_dispatch(u64 cgroup_id)
* v7.2: scx_bpf_cid_override() for explicit cpu->cid mapping. Ignore if
* missing.
*/
-void scx_bpf_cid_override___compat(const s32 *cpu_to_cid, u32 cpu_to_cid__sz) __ksym __weak;
+void scx_bpf_cid_override___compat(const s32 __arena *cpu_to_cid, u32 cnt) __ksym __weak;
-static inline void scx_bpf_cid_override(const s32 *cpu_to_cid, u32 cpu_to_cid__sz)
+static inline void scx_bpf_cid_override(const s32 __arena *cpu_to_cid, u32 cnt)
{
if (bpf_ksym_exists(scx_bpf_cid_override___compat))
- return scx_bpf_cid_override___compat(cpu_to_cid, cpu_to_cid__sz);
+ return scx_bpf_cid_override___compat(cpu_to_cid, cnt);
}
/**
diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
index fd9a82a67627..2b4cc55e04ce 100644
--- a/tools/sched_ext/scx_qmap.bpf.c
+++ b/tools/sched_ext/scx_qmap.bpf.c
@@ -63,13 +63,6 @@ const volatile u32 max_tasks;
* 3 = invalid: out-of-range cid
*/
const volatile u32 cid_override_mode;
-/*
- * Array lives in bss (writable) because scx_bpf_cid_override()'s BPF
- * verifier signature treats its len-paired pointer as read/write - rodata
- * fails verification with "write into map forbidden". Userspace populates
- * it before SCX_OPS_LOAD, same as rodata, and nothing writes it after.
- */
-s32 cid_override_cpu_to_cid[SCX_QMAP_MAX_CPUS];
UEI_DEFINE(uei);
@@ -1094,10 +1087,8 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(qmap_init)
* cid space (scx_bpf_nr_cids, cmask_init, etc.). On invalid input,
* the kfunc calls scx_error() which aborts the scheduler.
*/
- if (cid_override_mode) {
- scx_bpf_cid_override((const s32 *)cid_override_cpu_to_cid,
- nr_cpu_ids * sizeof(s32));
- }
+ if (cid_override_mode)
+ scx_bpf_cid_override(qa.cid_override_cpu_to_cid, nr_cpu_ids);
/*
* Allocate the task_ctx slab in arena and thread the entire slab onto
diff --git a/tools/sched_ext/scx_qmap.c b/tools/sched_ext/scx_qmap.c
index 67ddd483a4c7..c54f050d9991 100644
--- a/tools/sched_ext/scx_qmap.c
+++ b/tools/sched_ext/scx_qmap.c
@@ -153,8 +153,7 @@ int main(int argc, char **argv)
skel->rodata->immed_stress_nth = strtoul(optarg, NULL, 0);
break;
case 'C': {
- u32 nr_cpus = libbpf_num_possible_cpus();
- u32 mode, i;
+ u32 mode;
if (!strcmp(optarg, "shuffle"))
mode = 1;
@@ -167,18 +166,6 @@ int main(int argc, char **argv)
return 1;
}
skel->rodata->cid_override_mode = mode;
-
- /* shuffle: reversed cpu_to_cid, bad-dup: dup cid 0, bad-range: identity */
- for (i = 0; i < nr_cpus; i++) {
- if (mode == 1)
- skel->bss->cid_override_cpu_to_cid[i] = nr_cpus - 1 - i;
- else
- skel->bss->cid_override_cpu_to_cid[i] = i;
- }
- if (mode == 2 && nr_cpus >= 2)
- skel->bss->cid_override_cpu_to_cid[1] = 0;
- if (mode == 3)
- skel->bss->cid_override_cpu_to_cid[0] = (s32)nr_cpus;
break;
}
case 'v':
@@ -191,9 +178,33 @@ int main(int argc, char **argv)
}
SCX_OPS_LOAD(skel, qmap_ops, scx_qmap, uei);
- link = SCX_OPS_ATTACH(skel, qmap_ops, scx_qmap);
qa = &skel->arena->qa;
+
+ /*
+ * The cid-override array lives in the arena, which is mmapped at load.
+ * Populate it before qmap_init() consumes it at attach.
+ */
+ if (skel->rodata->cid_override_mode) {
+ u32 mode = skel->rodata->cid_override_mode;
+ u32 nr_cpus = libbpf_num_possible_cpus();
+ u32 i;
+
+ /* shuffle: reversed cpu_to_cid, bad-dup: dup cid 0, bad-range: identity */
+ for (i = 0; i < nr_cpus; i++) {
+ if (mode == 1)
+ qa->cid_override_cpu_to_cid[i] = nr_cpus - 1 - i;
+ else
+ qa->cid_override_cpu_to_cid[i] = i;
+ }
+ if (mode == 2 && nr_cpus >= 2)
+ qa->cid_override_cpu_to_cid[1] = 0;
+ if (mode == 3)
+ qa->cid_override_cpu_to_cid[0] = (s32)nr_cpus;
+ }
+
+ link = SCX_OPS_ATTACH(skel, qmap_ops, scx_qmap);
+
qa->test_error_cnt = test_error_cnt;
while (!exit_req && !UEI_EXITED(skel, uei)) {
diff --git a/tools/sched_ext/scx_qmap.h b/tools/sched_ext/scx_qmap.h
index d15a705d5ac5..3b01570bbde9 100644
--- a/tools/sched_ext/scx_qmap.h
+++ b/tools/sched_ext/scx_qmap.h
@@ -62,6 +62,9 @@ struct qmap_arena {
struct cpu_ctx cpu_ctxs[SCX_QMAP_MAX_CPUS];
+ /* cid-override test input, populated by the loader before attach */
+ __s32 cid_override_cpu_to_cid[SCX_QMAP_MAX_CPUS];
+
/* task_ctx slab; allocated and threaded by qmap_init() */
struct task_ctx __arena *task_ctxs;
struct task_ctx __arena *task_free_head;
--
2.55.0
next prev parent reply other threads:[~2026-07-13 2:44 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-13 2:44 [PATCHSET SLOP RFC 0/6] bpf: make arena pointers first-class kfunc and struct_ops arguments Tejun Heo
2026-07-13 2:44 ` [PATCHSET SLOP RFC 1/6] bpf: Support __arena suffix for kfunc arguments Tejun Heo
2026-07-13 2:58 ` sashiko-bot
2026-07-13 19:38 ` Tejun Heo
2026-07-13 21:45 ` Kumar Kartikeya Dwivedi
2026-07-13 2:44 ` [PATCHSET SLOP RFC 2/6] selftests/bpf: Add kfunc __arena argument tests Tejun Heo
2026-07-13 3:16 ` sashiko-bot
2026-07-13 19:38 ` Tejun Heo
2026-07-13 2:44 ` [PATCHSET SLOP RFC 3/6] bpf: Support __arena suffix on struct_ops stub arguments Tejun Heo
2026-07-13 2:59 ` sashiko-bot
2026-07-13 19:37 ` [PATCH v2 " Tejun Heo
2026-07-13 2:44 ` [PATCHSET SLOP RFC 4/6] selftests/bpf: Add struct_ops __arena argument tests Tejun Heo
2026-07-13 2:55 ` sashiko-bot
2026-07-13 19:38 ` Tejun Heo
2026-07-13 2:44 ` [PATCHSET SLOP RFC 5/6] sched_ext: Pass a kernel arena pointer to ops_cid.set_cmask() Tejun Heo
2026-07-13 2:44 ` Tejun Heo [this message]
2026-07-13 2:59 ` [PATCHSET SLOP RFC 6/6] sched_ext: Convert scx_bpf_cid_override() to take an arena pointer sashiko-bot
2026-07-13 19:38 ` Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260713024414.3759854-7-tj@kernel.org \
--to=tj@kernel.org \
--cc=andrii@kernel.org \
--cc=arighi@nvidia.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=changwoo@igalia.com \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=sched-ext@lists.linux.dev \
--cc=void@manifault.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.