summaryrefslogtreecommitdiff
path: root/tools/sched_ext
AgeCommit message (Collapse)Author
8 hoursMerge branch 'for-next' of ↵Mark Brown
https://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git
8 hoursMerge branch 'for-next' of ↵Mark Brown
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
23 hourstools/sched_ext: scx_qmap: Fix stale API name in commentLiang Luo
The comment above dispatch_highpri() still references scx_bpf_dispatch[_vtime]_from_dsq(), which was renamed to scx_bpf_dsq_move[_vtime]() in v6.13 to unload the overloaded "dispatch" verb. The code below already uses the new names; only the comment was left behind during the rename. Fixes: 5cbb302880f5 ("sched_ext: Rename scx_bpf_dispatch[_vtime]_from_dsq*() -> scx_bpf_dsq_move[_vtime]*()") Signed-off-by: Liang Luo <luoliang@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
36 hourstools/sched_ext: scx_qmap - Add sub-sched cap fault injectionTejun Heo
Add a fault-injection mode to the scx_qmap sub-scheduler that deliberately dispatches one of its own tasks to a cid it does not hold. The kernel cap check must reject it and re-enqueue with SCX_TASK_REENQ_CAP, so the nr_inject_attempts counter tracks nr_reenq_cap one to one, exercising the delivery-time cap enforcement. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
36 hourstools/sched_ext: scx_qmap - Expand hierarchical sub-schedulingTejun Heo
sched_ext sub-scheduling began as dispatch delegation only: a parent could call into a child cgroup sub-scheduler's ops.dispatch() from its own dispatch path, but could not delegate cpus to the child for enqueue and the other paths. sched_ext has since gained cap-based cid delegation, where a parent grants and revokes a child's per-cid caps. Expand scx_qmap to demonstrate it. scx_qmap can now delegate the cids it holds exclusively, split among itself and its children by cpu.weight. Each gets the floor of its share as dedicated cids. The leftover from rounding forms a shared pool, round-robined among them as an ENQ_IMMED time-share. This shape is deliberate. Exclusive cids exercise the basic grant and revoke of ownership, and the shared pool exercises time-sharing one cid across several schedulers. The implemented policy is impractical, but it covers most of what a practical sub-scheduler would need without overcomplicating qmap. Delegation nests. A cid a node receives from its parent only as a round-robin share stays self-local and is never re-delegated. A node left with no exclusive cid, e.g. after its cpus went offline, evicts its children. v5: Highpri dispatch masked with self_cids, single-read dispatch cgroup_id, feed_weights race comment. (sashiko AI) v4: Track all idle cids and mask with self_cids at the dispatch pick, dropping the reseed. (sashiko AI) v3: Dispatch IMMED flags, repartition accounting order, partition-input snapshot. (sashiko AI) v2: Use __sync_fetch_and_add() for the shared nr_dsps counter. (sashiko AI) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
36 hourstools/sched_ext: Add three-mask cmask intersection iteratorTejun Heo
Add cmask_next_and2_set() and its round-robin wrap, extending cmask_next_and_set() to a three-mask intersection: the next cid set in all three masks at or after @start. A caller iterating the intersection of three cmasks can then scan it in one pass, folding the third mask into the word-level AND rather than skipping non-members one candidate at a time. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
36 hourssched_ext: Add scx_bpf_sub_kill() to evict a child sub-schedulerTejun Heo
A cid-form scheduler can grant caps to and revoke them from its child sub-schedulers but has no way to tear one down. Add scx_bpf_sub_kill() to evict a direct child with a printf-style reason that reaches the child's scx_exit_info. No exit code is taken because the child is a separate scheduler whose exit-code semantics the parent cannot know. The child and its subtree are disabled through the usual async path under a new exit kind, SCX_EXIT_PARENT_KILL. The bstr formatting infrastructure in ext.c is exposed through internal.h with scx_ prefixes so the kfunc, which lives in sub.c, can format the reason. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
36 hourssched_ext: Add per-shard cap delegation for sub-schedulersTejun Heo
Caps are per-cid permissions parents delegate to direct children via scx_bpf_sub_grant() / scx_bpf_sub_revoke(). A child's cap set is always a subset of its parent's. Sub-scheds check their caps locally, and cross-sched communication is needed only when the delegation set itself changes. Caps will be used to implement sub-sched scheduling on the enqueue path. Picking a cid for a task at a leaf depends on which cids the leaf is allowed to use, and resolving that programmatically on every enqueue would mean a cross-sched round-trip call chain, possibly retrying if the request can't be granted as-is. The dispatch path is different - it runs as top-down recursion via scx_bpf_sub_dispatch(). Locking is per shard. cid space is split into shards, and each sub-sched has its own pshard->lock for each shard. Operations are broken up on shard boundaries. Different shards never contend. Shards are expected to be topology-aligned and likely to serve as the locality unit when cids are allocated to schedulers, so per-shard lock granularity scales naturally with the allocation pattern. This patch adds the framework with a single dummy cap. Real caps land in later patches. The enable path is reordered for pshards. scx_arena_pool_init() moves ahead of scx_link_sched() so the pshards are allocated before the sched becomes reachable - scx_alloc_pshards() skips allocation when the arena pool isn't initialized. - scx_bpf_sub_grant(): Per-cid all-or-nothing grant to direct child. - scx_bpf_sub_revoke(): Clear caps on @cmask across @child and its subtree. - scx_bpf_sub_caps(): Lockless snapshot of caps on a cid range. /sys/kernel/sched_ext/SCHED/caps shows the caps each scheduler currently holds. v4: Move the pshard[] full build/publish and the err_disable scx_error() recording to earlier patches. (sashiko AI) v3: Build pshard[] fully before publishing it, read it with READ_ONCE. (sashiko AI) v2: Validate ops before scx_link_sched() publishes the sub. (sashiko AI) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
36 hourssched_ext: Add shard boundaries to scx_bpf_cid_override()Tejun Heo
An overridden cid mapping invalidates the auto-generated shard layout, so the override call has to provide both. Extend scx_bpf_cid_override() with a shard_start[] array that lists the first cid of each shard (starting at 0, strictly increasing, last shard implicitly extends to num_possible_cpus()). A scheduler that wants only custom shards with the auto-generated cid mapping can read the current mapping and pass it back unchanged. Overridden shards can span NUMA nodes, so scx_shard_node[] is rebuilt by majority count: each shard is assigned to the node that owns the most cpus in it. v2: Snapshot the caller's cpu_to_cid/shard_start arrays before validating. (sashiko AI) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
36 hourssched_ext: Add ops.init_cids() to finalize the cid layout before initTejun Heo
A cid-form scheduler that calls scx_bpf_cid_override() to install a custom cid layout can only do so from ops.init(). Enable-path setup that depends on the cid layout thus has to run after ops.init(), and ops.init() itself can't use anything derived from the final layout, which turned out to be too restrictive. Add an ops.init_cids() callback dedicated to finalizing the cid layout. It runs before the rest of the enable-path setup, so the final layout is in effect for everything that follows including ops.init(), which now runs after the arena pool and cmask scratch allocations. scx_bpf_cid_override() is restricted to ops.init_cids() at load time. It sits in a kfunc set gated by SCX_KF_ALLOW_INIT_CIDS, a flag set only on the init_cids op, so the verifier rejects a call from any other context. The runtime root-only check is dropped as ops.init_cids() only runs during root enable. The qmap demo moves its override into a dedicated qmap_init_cids() and, while at it, introduces an enum for the cid override modes instead of hard-coded integers. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2 daystools/sched_ext: scx_flatcg: Fix uninitialized stats on allocation failureLiang Luo
In fcg_read_stats(), the memset() that zeroes the output @stats array sits after the calloc() failure check. When calloc() fails, the function returns without writing @stats. The caller in main() declares acc_stats uninitialized, passes it as the @stats argument, and then reads it unconditionally: __u64 acc_stats[FCG_NR_STATS]; fcg_read_stats(skel, acc_stats); stats[i] = acc_stats[i] - last_stats[i]; // reads garbage Because fcg_read_stats() returns void, the caller cannot detect the failure. Reading the uninitialized array is undefined behavior, and the garbage is further copied into last_stats via memcpy(), corrupting the baseline used by the next interval. This regression was introduced by commit cabd76bbc036 ("tools/sched_ext: scx_flatcg: fix potential stack overflow from VLA in fcg_read_stats"), which replaced the VLA with calloc() and inserted the failure check before the existing memset(). Move the memset() above the calloc() failure check so @stats is always zeroed regardless of allocation outcome. Fixes: cabd76bbc036 ("tools/sched_ext: scx_flatcg: fix potential stack overflow from VLA in fcg_read_stats") Signed-off-by: Liang Luo <luoliang@kylinos.cn> Reviewed-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
4 daysbpf: Require a BPF cpumask for bpf_cpumask_populate()Nicholas Dudar
bpf_cpumask_populate() writes to its destination with bitmap_copy(), but the destination is typed as struct cpumask *. That allows the verifier to accept borrowed cpumask pointers returned by read-only kfuncs, such as scx_bpf_get_online_cpumask(), as a writable destination. Make the destination a struct bpf_cpumask * so populate follows the same ownership rule as the other mutating cpumask kfuncs. Query kfuncs continue to accept const struct cpumask * inputs. Fixes: 950ad93df2fc ("bpf: add kfunc for populating cpumask bits") Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com> Acked-by: Tejun Heo <tj@kernel.org> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> Link: https://lore.kernel.org/bpf/20260709182800.2037938-2-main.kalliope@gmail.com Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
6 dayssched_ext: Make scx_bpf_kick_cid() return voidTejun Heo
scx_bpf_kick_cid() returned an error code, but the value conveys nothing actionable and no caller consumes it. The kick is asynchronous, so a successful return only means it was queued. An invalid @cid is already reported through scx_error() by scx_cid_to_cpu(), and a missing scheduler leaves nothing to kick. Make scx_bpf_kick_cid() return void to match scx_bpf_kick_cpu(). The cid-form kfuncs are not in practical use yet, so the ABI change is safe. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
6 daystools/sched_ext: scx_qmap - Use bare u64/u32/s32 integer typesTejun Heo
scx_qmap.c and the shared scx_qmap.h mixed __u64/__u32/__s32 with the bare typedefs that scx/common.h provides. Convert the remaining __-prefixed integer types to the bare forms for consistency. The struct fields become bare u64 (uint64_t), so the stats printfs that fed them to %llu now cast to unsigned long long. No functional change. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
6 daysMerge branch 'for-7.2-fixes' into for-7.3Tejun Heo
Pull to receive: db4e9defd2e8 ("sched_ext: Record an error on errno-only sub-enable failure") 49b3378a750c ("sched_ext: Fix premature ops->priv publication in scx_alloc_and_add_sched()") e6979d05c6a6 ("tools/sched_ext: scx - Fix cmask_subset(), cmask_equal() and cmask_weight()") for further sub-sched changes and to resolve the conflicts with the sub-sched updates on for-7.3. db4e9defd2e8 adds scx_error() to the sub-enable err_disable sink which for-7.3 moved from ext.c into sub.c. Resolved by applying the fix to scx_sub_enable_workfn() in sub.c. 49b3378a750c drops RCU_INIT_POINTER() from an scx_alloc_and_add_sched() unwind label whose body changed with for-7.3's stall_cpus addition. Resolved by dropping the line from the updated unwind. Signed-off-by: Tejun Heo <tj@kernel.org>
6 daystools/sched_ext: scx - Fix cmask_subset(), cmask_equal() and cmask_weight()Tejun Heo
cmask_equal(), cmask_weight() and cmask_subset() bounded their word walks with CMASK_NR_WORDS(nr_cids), which pads by one word and can't tell the last word in use without @base. The walks could thus cover a slack word past the active range, which cmask_reframe() leaves non-zero: a stale bit there gave cmask_equal() a spurious mismatch, cmask_weight() an inflated count, and cmask_subset() a spurious violation. cmask_subset() could also read @b->bits[] one word past its allocation (within the arena's fault-recovered range, so harmless), and deviated from the kernel scx_cmask_subset() by failing any @a range that doesn't nest inside @b's even when the overhanging bits are all clear. Bound the cmask_equal() and cmask_weight() walks by the words the range actually spans, with early returns for empty ranges. Rewrite cmask_subset() to match the kernel semantics: scan @a's overhangs for set bits with cmask_next_set() and walk the words of the range intersection. cmask_subset() moves below cmask_next_set(), which it now uses. Padding bits don't need masking as every cmask helper keeps them clear. Fixes: a58e6b79b432 ("sched_ext: Add cmask, a base-windowed bitmap over cid space") Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-06-30tools/sched_ext: use btf_vlen() helper in compat.hLiang Luo
__COMPAT_read_enum() and __COMPAT_struct_has_field() open-code the vlen lookup via the raw BTF_INFO_VLEN(t->info) UAPI macro. libbpf exposes btf_vlen() for exactly this purpose; use it in the three call sites, matching the pattern in kernel/bpf/inode.c and tools/bpf/bpftool. btf_vlen() returns __u32 (since commit cacd6729c0923, "libbpf: Adjust btf_vlen() to return a __u32", which expanded the BTF vlen field from 16 to 24 bits). Declare the loop counters as __u32 to match the return type, keeping the comparison as a plain '__u32 < __u32' and silencing the -Wsign-compare warnings. No functional change. Suggested-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Liang Luo <luoliang@kylinos.cn> Reviewed-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-06-26tools/sched_ext: fix getopt() option variable signednessLiang Luo
Four example schedulers (scx_simple, scx_cpu0, scx_sdt, scx_userland) declare the variable that holds getopt()'s return value as __u32. getopt() returns int and uses -1 to mark end-of-options; storing that sentinel in an unsigned variable turns it into 0xffffffff, and the subsequent 'opt != -1' test only happens to keep working because both operands of != are promoted to the same 0xffffffff. Declare the variable as __s32 instead, matching getopt()'s actual contract and the style already used in scx_qmap.c (int opt) and scx_pair/central/flatcg.c (__s32 opt). This also silences the -Wsign-compare warnings emitted for the affected files. Signed-off-by: Liang Luo <luoliang@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-06-24sched_ext/scx_flatcg: Fix cvtime_delta race and add hweight scaling to ↵Wanwu Li
bypass charging 1. cgrp_cap_budget() used __sync_fetch_and_sub(&cgc->cvtime_delta, cgc->cvtime_delta) to atomically read and clear cvtime_delta. However, this is not a true atomic read-clear operation: the second argument (cgc->cvtime_delta) is evaluated as a normal read before the atomic fetch_and_sub executes. If a concurrent __sync_fetch_and_add() happens between the read and the sub, the added value gets included in the returned delta AND remains in cvtime_delta, causing double charging. Example: CPU 0 runs cgrp_cap_budget(), CPU 1 runs fcg_stopping(). Assume cvtime_delta = 100 initially. T1 CPU 0: sub_val = cvtime_delta = 100 cvtime_delta = 100 T2 CPU 1: __sync_fetch_and_add(&cvtime_delta, 10) cvtime_delta = 110 T3 CPU 0: __sync_fetch_and_sub(&cvtime_delta, sub_val) cvtime_delta = 10 returns old=110 delta = 110 (includes the 10 from CPU 1), but cvtime_delta = 10 (the 10 also remains). The 10 is charged twice: once in delta (applied to cgv_node->cvtime) and once in the residual cvtime_delta (fetched again next time). Fix by using __sync_fetch_and_and(&cgc->cvtime_delta, 0). Disassembly comparison: (1) delta = __sync_fetch_and_sub(&cgc->cvtime_delta, cgc->cvtime_delta); 228: (79) r7 = *(u64 *)(r9 +40) 229: (87) r7 = -r7 230: (db) r7 = atomic64_fetch_add((u64 *)(r9 +40), r7) //r9 may be changed (2) delta = __sync_fetch_and_and(&cgc->cvtime_delta, 0); 228: (b7) r8 = 0 229: (db) r8 = atomic64_xchg((u64 *)(r9 +40), r8) 2. The bypass charging path in fcg_stopping() charges raw execution time to cvtime_delta without scaling by the inverse of the cgroup hweight. Since cvtime_delta is eventually applied to cgv_node->cvtime which is in vtime space (weight-scaled), the bypass path should also scale by FCG_HWEIGHT_ONE / hweight to match the units used by the dispatch path. Fixes: a4103eacc2ab ("sched_ext: Add a cgroup scheduler which uses flattened hierarchy") Signed-off-by: Wanwu Li <liwanwu@kylinos.cn> Reviewed-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-06-24sched_ext: Remove deprecated scx_bpf_cpu_rq()Christian Loehle
scx_bpf_cpu_rq() exposes rq pointers without requiring the rq lock and has emitted a deprecation warning since commit 5c48d88fe004 ("sched_ext: deprecation warn for scx_bpf_cpu_rq()"). The supported replacements cover the intended uses: scx_bpf_locked_rq() for locked rq access and scx_bpf_cpu_curr() for remote curr lookup. Remove the kfunc, its BTF registrations, the deprecation warning state, and the BPF-side prototype and compat fallback. Signed-off-by: Christian Loehle <christian.loehle@arm.com> Reviewed-by: Andrea Righi <arighi@nvidia.com> Reviewed-by: Hongyan Xia <hongyan.xia@transsion.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-06-22sched_ext: Move sources under kernel/sched/ext/Tejun Heo
The sched_ext sources had grown to ten ext* files directly under kernel/sched/. Move them into a new kernel/sched/ext/ subdirectory and drop the now-redundant ext_ prefix. ext.c/h keep their names. kernel/sched/ext.{c,h} -> kernel/sched/ext/ext.{c,h} kernel/sched/ext_internal.h -> kernel/sched/ext/internal.h kernel/sched/ext_types.h -> kernel/sched/ext/types.h kernel/sched/ext_idle.{c,h} -> kernel/sched/ext/idle.{c,h} kernel/sched/ext_cid.{c,h} -> kernel/sched/ext/cid.{c,h} kernel/sched/ext_arena.{c,h} -> kernel/sched/ext/arena.{c,h} The include paths in build_policy.c and sched.h, the MAINTAINERS glob, and a few documentation and comment references are updated to match. No code or symbol changes. Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Reviewed-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-06-17Merge tag 'sched_ext-for-7.2' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext Pull sched_ext updates from Tejun Heo: "Most of this continues the in-development sub-scheduler support, which lets a root BPF scheduler delegate to nested sub-schedulers. The dispatch-path building blocks landed in 7.1. A follow-up patchset in development will complete enqueue-path support for hierarchical scheduling. This cycle adds most of that infrastructure: - Topological CPU IDs (cids): a dense, topology-ordered CPU numbering where the CPUs of a core, LLC, or NUMA node form contiguous ranges, so a topology unit becomes a (start, length) slice. Raw CPU numbers are sparse and don't track topological closeness, which makes them clumsy for sharding work across sub-schedulers and awkward in BPF. - cmask: bitmaps windowed over a slice of cid space, so a sub-scheduler can track, for example, the idle cids of its shard without a full NR_CPUS cpumask. - A struct_ops variant that cid-form sub-schedulers register with, along with the cid-form kfuncs they call. - BPF arena integration, which sub-scheduler support is built on. The bpf-next additions let the kernel read and write the BPF scheduler's arena directly, turning it into a real kernel/BPF shared-memory channel. Shared state like the per-CPU cmask now lives there. - scx_qmap is reworked to exercise the new arena and cid interfaces. Additionally: - Exit-dump improvements: dump the faulting CPU first, expose the exit CPU to BPF and userspace, and normalize the dump header. - Misc kfuncs and cleanups: a task-ID lookup kfunc, __printf checking on the error and dump formatters, header reorganization, and assorted fixes" * tag 'sched_ext-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext: (59 commits) sched_ext: Add scx_arena_to_kaddr() / scx_kaddr_to_arena() sched_ext: Make scx_bpf_kick_cid() return s32 sched_ext: Add scx_cmask_test() and scx_cmask_for_each_cid() tools/sched_ext: Order single-cid cmask helpers as (cid, mask) sched_ext: Order single-cid cmask helpers as (cid, mask) selftests/sched_ext: Fix dsq_move_to_local check sched_ext: Guard BPF arena helper calls to fix 32-bit build sched_ext: idle: Fix errno loss in scx_idle_init() sched_ext: Convert ops.set_cmask() to arena-resident cmask sched_ext: Sub-allocator over kernel-claimed BPF arena pages sched_ext: Require an arena for cid-form schedulers sched_ext: Add cmask mask ops sched_ext: Track bits[] storage size in struct scx_cmask sched_ext: Rename scx_cmask.nr_bits to nr_cids tools/sched_ext: scx_qmap: Fix qa arena placement sched_ext: Mark !CONFIG_EXT_SUB_SCHED dummy stubs static inline sched_ext: Replace tryget_task_struct() with get_task_struct() sched_ext: Add scx_task_iter_relock() and use it in scx_root_enable_workfn() sched_ext: Fix ops_cid layout assert sched_ext: Use offsetofend on both sides of the ops_cid layout assert ...
2026-06-03sched_ext: Make scx_bpf_kick_cid() return s32Tejun Heo
Switch scx_bpf_kick_cid() from void to s32 so future cap enforcement can surface failures. cid interface is introduced in this cycle and has no external users, so the ABI change is safe. Subsequent patches will add -EPERM returns when the calling sub-sched lacks the required cap on the target cid. v2: Return scx_cid_to_cpu()'s errno instead of -EINVAL. (Andrea) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-06-03tools/sched_ext: Order single-cid cmask helpers as (cid, mask)Tejun Heo
The BPF arena single-cid cmask helpers take the cmask first and the cid second. Reorder them to (cid, mask) to match the kernel-side helpers and the test_bit(nr, addr), cpumask_test_cpu(cpu, mask) convention. Range and iteration helpers keep (mask, start). Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-05-27tools/sched_ext: Fix scx_show_state per-scheduler state readsZicheng Qu
scx_show_state.py still reads scx_aborting and scx_bypass_depth as global symbols. Those symbols no longer exist after the state was moved into struct scx_sched, so the drgn script fails when it reaches either field. Read aborting and bypass_depth from scx_root instead. This preserves the script's current root-scheduler view: with sub-scheduler support, the reported values are for the root scheduler and sub-schedulers are not enumerated. Fixes: 5c8d98a1b4de ("sched_ext: Move bypass state into scx_sched") Fixes: c1743da43cf5 ("sched_ext: Move aborting flag to per-scheduler field") Signed-off-by: Zicheng Qu <quzicheng@huawei.com> Reviewed-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-05-25sched_ext: Convert ops.set_cmask() to arena-resident cmaskTejun Heo
ops_cid.set_cmask() expects a cmask. The kernel couldn't write into the arena, so it translated cpumask -> cmask in kernel memory and passed the result as a trusted pointer. The BPF cmask helpers all operate on arena cmasks though, so the BPF side had to word-by-word probe-read the kernel cmask into an arena cmask via cmask_copy_from_kernel() before any helper could touch it. It works, but is clumsy. With direct kernel-side arena access now in place, build the cmask in the arena. The kernel writes to it through the kern_va side of the dual mapping. BPF directly dereferences it via an __arena pointer like any other arena struct. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
2026-05-20sched_ext: Track bits[] storage size in struct scx_cmaskTejun Heo
scx_cmask carries @base and @nr_cids but not the bits[] allocation size, so helpers reshaping the active range have no way to check it fits and later kfuncs taking caller-provided storage can't validate it. Add @alloc_words (u64 word count) annotated with __counted_by, and split the bit-range API into three helpers: - SCX_CMASK_DEFINE() / __SCX_CMASK_DEFINE() define an on-stack cmask, the latter taking an explicit capacity for oversized storage. SCX_CMASK_DEFINE_SHARD() is a thin wrapper that always reserves SCX_CID_SHARD_MAX_CPUS bits of storage. - scx_cmask_init() / __scx_cmask_init() initialize a cmask, with the same tight-vs-explicit split. - scx_cmask_reframe() reshapes the active range without resizing storage. The BPF mirror (cmask_init / __cmask_init / cmask_reframe) gets the same shape. Add scx_cmask_clear() and scx_cmask_fill() to zero and set the active-range bits respectively. scx_cpumask_to_cmask() uses scx_cmask_clear(); scx_cmask_init() would otherwise re-write @alloc_words on every call. A later patch uses @alloc_words in scx_cmask_ref_shard() to refuse output storage that can't hold the requested shard. v2: Init per-CPU scx_set_cmask_scratch (was zero-init, emitted empty cmasks). Add nr_cids/alloc_cids check in BPF __cmask_init(). (sashiko AI) Widen SCX_CMASK_NR_WORDS()/CMASK_NR_WORDS() to compute in u64 so that @nr_cids near U32_MAX no longer wraps to a small value and bypasses the bounds check in cmask_reframe(). (Andrea) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-05-20sched_ext: Rename scx_cmask.nr_bits to nr_cidsTejun Heo
struct scx_cmask is a base-windowed bitmap over cid space. Each bit represents one cid, so the count of active bits is the count of cids. The sibling struct scx_cid_shard already uses nr_cids. Rename as a prep so the following patches that grow the cmask API can use the consistent name. v2: Also rename src->nr_bits / dst->nr_bits in cmask_copy_from_kernel(). (sashiko AI) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-05-13tools/sched_ext: scx_qmap: Fix qa arena placementCheng-Yang Chou
__arena is a pointer qualifier meaning "this pointer points to arena memory". When used on a global variable declaration, it expands to nothing in scx's build because __BPF_FEATURE_ADDR_SPACE_CAST is never defined, leaving qa as a plain global in BSS. bpftool then generates skel->bss->qa instead of the expected skel->arena->qa, causing: scx_qmap.c: error: 'struct scx_qmap' has no member named 'arena' __arena_global is the correct annotation for global variables that reside in the arena. When __BPF_FEATURE_ADDR_SPACE_CAST is not defined it expands to SEC(".addr_space.1"), placing qa in the arena ELF section. When __BPF_FEATURE_ADDR_SPACE_CAST is defined it expands to __attribute__((address_space(1))). In both cases bpftool generates the typed skel->arena accessor. Fixes: 60a59eaca71b ("sched_ext: scx_qmap: move globals and cpu_ctx into a BPF arena map") Signed-off-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-29tools/sched_ext: scx_qmap: Port to cid-form struct_opsTejun Heo
Flip qmap's struct_ops to bpf_sched_ext_ops_cid. The kernel now passes cids and cmasks to callbacks directly, so the per-callback cpu<->cid translations that the prior patch added drop out and cpu_ctxs[] is reindexed by cid. Cpu-form kfunc calls switch to their cid-form counterparts. The cpu-only kfuncs (idle/any pick, cpumask iteration) have no cid substitute. Their callers already moved to cmask scans against qa_idle_cids and taskc->cpus_allowed in the prior patch, so the kfunc calls drop here without behavior changes. set_cmask is wired up via cmask_copy_from_kernel() to copy the kernel-supplied cmask into the arena-resident taskc cmask. The cpuperf monitor iterates the cid-form perf kfuncs. v4: Match scx_bpf_cid_override()'s 2-arg form, drop the shard test plumbing, bound nr_cpu_ids for the verifier, and switch mode 3 from bad-mono to bad-range (Changwoo, Andrea). Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-29tools/sched_ext: scx_qmap: Add cmask-based idle tracking and cid-based idle pickTejun Heo
Switch qmap's idle-cpu picker from scx_bpf_pick_idle_cpu() to a BPF-side bitmap scan, still under cpu-form struct_ops. qa_idle_cids tracks idle cids (updated in update_idle / cpu_offline) and each task's taskc->cpus_allowed tracks its allowed cids (built in set_cpumask / init_task); select_cpu / enqueue scan the intersection for an idle cid. Callbacks translate cpu <-> cid on entry; cid-qmap-port drops those translations. The scan is barebone - no core preference or other topology-aware picks like the in-kernel picker - but qmap is a demo and this is enough to exercise the plumbing. v3: qmap_init() refuses to load when nr_cids exceeds SCX_QMAP_MAX_CPUS; task_ctx's flex array would otherwise overflow into the next slab entry. (Sashiko) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-29tools/sched_ext: scx_qmap: Restart on hotplug instead of cpu_online/offlineTejun Heo
The cid mapping is built from the online cpu set at scheduler enable and stays valid for that set; routine hotplug invalidates it. The default cid behavior is to restart the scheduler so the mapping gets rebuilt against the new online set, and that requires not implementing cpu_online / cpu_offline (which suppress the kernel's ACT_RESTART). Drop the two ops along with their print_cpus() helper - the cluster view was only useful as a hotplug demo and is meaningless over the dense cid space the scheduler will move to. Wire main() to handle the ACT_RESTART exit by reopening the skel and reattaching, matching the pattern in scx_simple / scx_central / scx_flatcg etc. Reset optind so getopt re-parses argv into the fresh skel rodata each iteration. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-29sched_ext: Add bpf_sched_ext_ops_cid struct_ops typeTejun Heo
cpumask is awkward from BPF and unusable from arena; cid/cmask work in both. Sub-sched enqueue will need cmask. Without a full cid interface, schedulers end up mixing forms - a subtle-bug factory. Add sched_ext_ops_cid, which mirrors sched_ext_ops with cid/cmask replacing cpu/cpumask in the topology-carrying callbacks. cpu_acquire/cpu_release are deprecated and absent; a prior patch moved them past @priv so the cid-form can omit them without disturbing shared-field offsets. The two structs share byte-identical layout up to @priv, so the existing bpf_scx init/check hooks, has_op bitmap, and scx_kf_allow_flags[] are offset-indexed and apply to both. BUILD_BUG_ON in scx_init() pins the shared-field and renamed-callback offsets so any future drift trips at boot. The kernel<->BPF boundary translates between cpu and cid: - A static key, enabled on cid-form sched load, gates the translation so cpu-form schedulers pay nothing. - dispatch, update_idle, cpu_online/offline and dump_cpu translate the cpu arg at the callsite. - select_cpu also translates the returned cid back to a cpu. - set_cpumask is wrapped to synthesize a cmask in a per-cpu scratch before calling the cid-form callback. All scheds in a hierarchy share one form. The static key drives the hot-path branch. v2: Use struct_size() for the set_cmask_scratch percpu alloc. Move cid-shard fields and assertions into the later cid-shard patch. v3: Drop `static` on scx_set_cmask_scratch; add extern in ext_internal.h. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-29sched_ext: Add cid-form kfunc wrappers alongside cpu-formTejun Heo
cpumask is awkward from BPF and unusable from arena; cid/cmask work in both. Sub-sched enqueue will need cmask. Without full cid coverage a scheduler has to mix cid and cpu forms, which is a subtle-bug factory. Close the gap with a cid-native interface. Pair every cpu-form kfunc that takes a cpu id with a cid-form equivalent (kick, task placement, cpuperf query/set, per-cpu current task, nr-cpu-ids). Add two cid-natives with no cpu-form sibling: scx_bpf_this_cid() (cid of the running cpu, scx equivalent of bpf_get_smp_processor_id) and scx_bpf_nr_online_cids(). scx_bpf_cpu_rq is deprecated; no cid-form counterpart. NUMA node info is reachable via scx_bpf_cid_topo() on the BPF side. Each cid-form wrapper is a thin cid -> cpu translation that delegates to the cpu path, registered in the same context sets so usage constraints match. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-29sched_ext: Add cmask, a base-windowed bitmap over cid spaceTejun Heo
Sub-scheduler code built on cids needs bitmaps scoped to a slice of cid space (e.g. the idle cids of a shard). A cpumask sized for NR_CPUS wastes most of its bits for a small window and is awkward in BPF. scx_cmask covers [base, base + nr_bits). bits[] is aligned to the global 64-cid grid: bits[0] spans [base & ~63, (base & ~63) + 64). Any two cmasks therefore address bits[] against the same global windows, so cross-cmask word ops reduce to dest->bits[i] OP= operand->bits[i - delta] with no bit-shifting, at the cost of up to one extra storage word for head misalignment. This alignment guarantee is the reason binary ops can stay word-level; every mutating helper preserves it. Kernel side in ext_cid.[hc]; BPF side in tools/sched_ext/include/scx/ cid.bpf.h. BPF side drops the scx_ prefix (redundant in BPF code) and adds the extra helpers that basic idle-cpu selection needs. No callers yet. v2: Narrow to helpers that will be used in the planned changes; set/bit/find/zero ops will be added as usage develops. v3: cmask_copy_from_kernel: validate src->base == 0 via probe-read; bit-level nr_bits check instead of round-up word count. (Sashiko) v4: Bump CMASK_CAS_TRIES to 1<<23 so abort fires only after seconds of real spinning, not on plausible contention. Switch __builtin_ctzll() to the ctzll() wrapper for clang compat (Changwoo). Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-29tools/sched_ext: Add struct_size() helpers to common.bpf.hTejun Heo
Add flex_array_size(), struct_size() and struct_size_t() to scx/common.bpf.h so BPF schedulers can size flex-array-containing structs the same way kernel code does. These are abbreviated forms of the <linux/overflow.h> macros. v3: Use offsetof() instead of sizeof() in struct_size() to match kernel semantics (no inflation from trailing struct padding). (Sashiko) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-29sched_ext: Add scx_bpf_cid_override() kfuncTejun Heo
The auto-probed cid mapping reflects the kernel's view of topology (node -> LLC -> core), but a BPF scheduler may want a different layout - to align cid slices with its own partitioning, or to work around how the kernel reports a particular machine. Add scx_bpf_cid_override(), callable from ops.init() of the root scheduler. It validates the caller-supplied cpu->cid array and replaces the in-place mapping; topo info is invalidated. A compat.bpf.h wrapper silently no-ops on kernels that lack the kfunc. A new SCX_KF_ALLOW_INIT bit in the kfunc context filter restricts the kfunc to ops.init() at verifier load time. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com>
2026-04-29sched_ext: Add topological CPU IDs (cids)Tejun Heo
Raw cpu numbers are clumsy for sharding and cross-sched communication, especially from BPF. The space is sparse, numerical closeness doesn't track topological closeness (x86 hyperthreading often scatters SMT siblings), and a range of cpu ids doesn't describe anything meaningful. Sub-sched support makes this acute: cpu allocation, revocation, and state constantly flow across sub-scheds. Passing whole cpumasks scales poorly (every op scans 4K bits) and cpumasks are awkward in BPF. cids assign every cpu a dense, topology-ordered id. CPUs sharing a core, LLC, or NUMA node occupy contiguous cid ranges, so a topology unit becomes a (start, length) slice. Communication passes slices; BPF can process a u64 word of cids at a time. Build the mapping once at root enable by walking online cpus node -> LLC -> core. Possible-but-not-online cpus tail the space with no-topo cids. Expose kfuncs to map cpu <-> cid in either direction and to query each cid's topology metadata. v2: Use kzalloc_objs()/kmalloc_objs() for the three allocs in scx_cid_arrays_alloc() (Cheng-Yang Chou). v3: scx_cid_init() failure path now drops cpus_read_lock(); BUILD_BUG_ON tightened to match BPF cmask helpers' NR_CPUS<=8192. (Sashiko) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-28sched_ext: Expose exit_cpu to BPF and userspaceChangwoo Min
Extend struct user_exit_info with an exit_cpu field so BPF schedulers and the userspace report path can see the CPU that triggered the exit, matching the kernel-side dump. UEI_RECORD() defaults the field to -1 before the CO-RE-gated copy so that running against an older kernel without exit_cpu stays distinguishable from "exit happened on CPU 0". UEI_REPORT() appends "on CPU N" to the EXIT line when the value is valid, surfacing the most diagnostically useful piece of exit info to any sched_ext userspace tool without needing to crack open the debug dump. Signed-off-by: Changwoo Min <changwoo@igalia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-21Merge branch 'for-7.1-fixes' into for-7.2Tejun Heo
Pull to receive: 05909810a946 ("tools/sched_ext: scx_qmap: Silence task_ctx lookup miss") which conflicts with the cid-form qmap rework on for-7.2. Resolved by applying the same silence-on-NULL semantics to the arena-backed lookup_task_ctx() and qmap_select_cpu() on for-7.2. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-21tools/sched_ext: scx_qmap: Silence task_ctx lookup missTejun Heo
scx_fork() dispatches ops.init_task to exactly one scheduler - the one owning the forking task's cgroup. A task forked inside a sub-scheduler's cgroup is init'd into the sub only; the root scheduler has no task_ctx entry for it. When that task later appears as @prev in the root's qmap_dispatch() (or flows through core-sched comparison via task_qdist), the bpf_task_storage_get() legitimately misses. qmap treated those misses as fatal via scx_bpf_error("task_ctx lookup failed") and aborted the scheduler as soon as the first cross-sched task hit the root. Drop the error in the sites where the miss is legitimate: lookup_task_ctx() (helper; callers already check for NULL), qmap_dispatch()'s @prev branch (bookkeeping-only), task_qdist() (returns 0 which makes the comparison a no-op), and qmap_select_cpu() (returns prev_cpu as a no-op fallback instead of -ESRCH). The existing scx_error was a paranoid guard from the pre-sub-sched world where every task was owned by the one and only scheduler. v2: qmap_select_cpu() returns prev_cpu on NULL instead of -ESRCH, so the root scheduler doesn't error on cross-sched tasks that pass through it (Andrea Righi). Fixes: 4f8b122848db ("sched_ext: Add basic building blocks for nested sub-scheduler dispatching") Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com> Reviewed-by: Zhao Mengmeng <zhaomengmeng@kylinos.cn>
2026-04-20tools/sched_ext: Remove unused nr_cpus in scx_cpu0Cheng-Yang Chou
The nr_cpus variable is defined in scx_cpu0.bpf.c but never used in the BPF logic. Remove both in BPF and userspace side. Signed-off-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-20sched_ext: Documentation: clarify arena-backed doubly-linked lists in scx_qmapCheng-Yang Chou
Update scx_qmap description to reflect arena-backed doubly-linked lists with per-queue bpf_res_spin_lock. Also update scx_qmap.bpf.c to reflect switch from PIDs to TIDs. Suggested-by: Tejun Heo <tj@kernel.org> Signed-off-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-20sched_ext: add p->scx.tid and SCX_OPS_TID_TO_TASK lookupTejun Heo
BPF schedulers that can't hold task_struct pointers (arena-backed ones in particular) key tasks by pid. During exit, pid is released before the task finishes passing through scheduler callbacks, so a dying task becomes invisible to the BPF side mid-schedule. scx_qmap hits this: an exiting task's dispatch callback can't recover its queue entry, stalling dispatch until SCX_EXIT_ERROR_STALL. Add a unique non-zero u64 p->scx.tid assigned at fork that survives the full task lifetime including exit. scx_bpf_tid_to_task() looks up the task; unlike bpf_task_from_pid(), it handles exiting tasks. The lookup costs an rhashtable insert/remove under scx_tasks_lock, so root schedulers opt in via SCX_OPS_TID_TO_TASK. Sub-schedulers that set the flag to declare a dependency are rejected at attach if root didn't opt in. scx_qmap converted: keys tasks by tid and enables SCX_OPS_ENQ_EXITING. Pre-patch it stalls within seconds under a non-leader-exec workload; with the patch it runs cleanly. v3: Warn on rhashtable_lookup_insert_fast() failure via new scx_tid_hash_insert() helper (Cheng-Yang Chou). v2: Guard scx_root deref in scx_bpf_tid_to_task() error path. The kfunc is registered via scx_kfunc_set_any and reachable from tracing and syscall programs when no scheduler is attached (Cheng-Yang Chou). Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-04-20tools/sched_ext: Remove dead -d option in scx_flatcgCheng-Yang Chou
The -d option was non-functional, only toggling a variable that was echoed in the status line but never used to dump the cgroup hierarchy. Remove the option to avoid documenting dead code as a feature. Suggested-by: Tejun Heo <tj@kernel.org> Signed-off-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-19sched_ext: Document the ops compat strategy in compat.h/compat.bpf.hTejun Heo
The comments around SCX_OPS_DEFINE() and SCX_OPS_OPEN() were vague about how backward compatibility actually works. Expand them to describe the two mechanisms: load-time BTF fix-up for additive changes, and multi-variant struct_ops for incompatible ones. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Andrea Righi <arighi@nvidia.com> Acked-by: Cheng-Yang Chou <yphbchou0911@gmail.com>
2026-04-17tools/sched_ext: Add missing -c option in scx_qmap helpZhao Mengmeng
The sub-scheduler api has been added to scx_qmap, but the new -c option is missing in help, which is hard to understand and use. Add it in help. V2: add [-c CG_PATH] to the usage synopsis. Signed-off-by: Zhao Mengmeng <zhaomengmeng@kylinos.cn> Reviewed-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-17tools/sched_ext: Handle migration-disabled tasks in scx_centralCheng-Yang Chou
When a task calls migrate_disable(), p->cpus_ptr is not updated until migrate_disable_switch() runs during context switch, so dispatch_to_cpu() may dequeue such a task and dispatch it to a CPU it cannot run on. Extend the mismatch check in dispatch_to_cpu() to also test is_migration_disabled() alongside the cpumask check, so tasks in this window are bounced to the fallback DSQ. Suggested-by: Andrea Righi <arighi@nvidia.com> Suggested-by: Tejun Heo <tj@kernel.org> Suggested-by: Kuba Piecuch <jpiecuch@google.com> Signed-off-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Kuba Piecuch <jpiecuch@google.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-04-16sched_ext: scx_qmap: replace FIFO queue maps with arena-backed listsTejun Heo
Arena simplifies verification and allows more natural programming. Convert scx_qmap to arena as preparation for further sub-sched work. Replace the five BPF_MAP_TYPE_QUEUE maps with doubly-linked lists in arena, threaded through task_ctx. Each queue is a struct qmap_fifo with head/tail pointers and its own per-queue bpf_res_spin_lock. qmap_dequeue() now properly removes tasks from the queue instead of leaving stale entries for dispatch to skip. v2: - Remove duplicate QMAP_TOUCH_ARENA() in qmap_dump_task (Andrea). - Update file-level description for arena-backed lists (Andrea). Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
2026-04-16sched_ext: scx_qmap: move task_ctx into a BPF arena slabTejun Heo
Arena simplifies verification and allows more natural programming. Convert scx_qmap to arena as preparation for further sub-sched work. Allocate per-task context from an arena slab instead of storing it directly in task_storage. task_ctx_stor now holds an arena pointer to the task's slab entry. Free entries form a singly-linked list protected by bpf_res_spin_lock; slab exhaustion triggers scx_bpf_error(). The slab size is configurable via the new -N option (default 16384). Also add bpf_res_spin_lock/unlock declarations to common.bpf.h. Scheduling logic unchanged. v2: Add task_ctx_t typedef for struct task_ctx __arena (Emil). Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>