summaryrefslogtreecommitdiff
path: root/tools/sched_ext
AgeCommit message (Collapse)Author
3 daysMerge branch 'for-next' of ↵Mark Brown
https://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git
3 daysmm: replace PF_KCOMPACTD flag with kthread_func() checkKefeng Wang
PF_KCOMPACTD was introduced by commit ce6d9c1c2b5c ("NFS: fix nfs_release_folio() to not deadlock via kcompactd writeback") so nfs_release_folio() could detect kcompactd context and skip writeback. The flag is only consumed by current_is_kcompactd(), whose sole caller is nfs_release_folio(). Replace the flag-based check with kthread_func(current) == kcompactd, freeing the 0x00010000 PF flag bit. Link: https://lore.kernel.org/20260902131653.1338227-5-wangkefeng.wang@huawei.com Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Acked-by: Shakeel Butt <shakeel.butt@linux.dev> Acked-by: Zi Yan <ziy@nvidia.com> Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org> Reviewed-by: David Hildenbrand (Arm) <david@kernel.org> Cc: Brendan Jackman <brendan.jackman@linux.dev> Cc: Carlos Maiolino <cem@kernel.org> Cc: Christian Brauner <brauner@kernel.org> Cc: Christoph Hellwig <hch@lst.de> Cc: "Darrick J. Wong" <djwong@kernel.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Lorenzo Stoakes <ljs@kernel.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Suren Baghdasaryan <surenb@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysmm: replace PF_KSWAPD flag with kthread_func() checkKefeng Wang
The preceding commits removed the last consumer that propagated PF_KSWAPD beyond kswapd itself (XFS btree split worker inheritance). The only remaining setter of PF_KSWAPD is kswapd(), and every current_is_kswapd() caller only needs to check whether the current task *is* the kswapd thread, not whether it inherited the flag. Replace the flag-based test with kthread_func(current) == kswapd, freeing the 0x00020000 PF flag bit. Link: https://lore.kernel.org/20260902131653.1338227-4-wangkefeng.wang@huawei.com Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Acked-by: Shakeel Butt <shakeel.butt@linux.dev> Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org> Acked-by: Zi Yan <ziy@nvidia.com> Cc: Brendan Jackman <brendan.jackman@linux.dev> Cc: Carlos Maiolino <cem@kernel.org> Cc: Christian Brauner <brauner@kernel.org> Cc: Christoph Hellwig <hch@lst.de> Cc: "Darrick J. Wong" <djwong@kernel.org> Cc: David Hildenbrand <david@kernel.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Lorenzo Stoakes <ljs@kernel.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Suren Baghdasaryan <surenb@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
6 daysMerge branch 'for-7.4' into for-nextTejun Heo
6 daystools/sched_ext: Fix repeated word 'be' in commentHemanth Selam
Drop the second 'be', reported by checkpatch.pl as a possible repeated word. Only touches a comment, no code changes. Assisted-by: Cursor:claude-opus-5 Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org>
6 daysMerge branch 'for-7.4' into for-nextTejun Heo
6 daystools/sched_ext: Drop the no-op -rdynamic from CFLAGSCheng-Yang Chou
Because CFLAGS only applies to compilation ($(CC) -c), the link-time flag -rdynamic is inert during the build. Schedulers do not rely on exported dynamic symbols, and binaries remain byte-identical without it. Under -Werror, Clang treats this unused argument as a build error: $ make CC=clang-21 clang-21: error: argument unused during compilation: '-rdynamic' [-Werror,-Wunused-command-line-argument] Drop -rdynamic from CFLAGS to ensure clean builds across Clang versions. Signed-off-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org>
7 daysMerge branch 'for-7.3-fixes' into for-nextTejun Heo
7 dayssched_ext: scx_qmap: Fix pending partition work handoffTejun Heo
qmap can leave partition work pending with no runner. The effective-cap callback publishes its request after failing to acquire part_busy, while redistribute() checks for pending work before releasing it. Either ordering can miss a request arriving as the current runner finishes, delaying the update until the round-robin timer runs. Publish requests before trying to become the runner and release part_busy before checking for more work. Have all holders drain pending requests after releasing it, including the stats flush. Distinguish mask refreshes from repartitions so an effective-cap update only rebuilds the partition when a repartition was also requested. Fixes: e9151ed5c944 ("tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling") Reported-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
8 daysMerge branch 'for-7.3-fixes' into for-nextTejun Heo
8 dayssched_ext: scx_qmap: Place only on cids whose caps are in effectTejun Heo
qmap decides placements from self_cids, which redistribute() derives from the caps view at ops.sub_caps_updated() time. That view runs ahead of the cpus: a granted cid can be in self_cids before its cpu has reported the caps in effect through ops.sub_ecaps_updated(). ops.update_idle() only comes once BASE is in effect, so the idle-gated placements reach such a cid only through an idle bit left over from an earlier hold. The highpri scan has no gate at all: parent cpu Y, qmap cpu X grants ENQ on X to qmap sub_caps_updated() adds X to self_cids highpri scan moves a task to X with PREEMPT caps not in effect, move denied, task bounced with REENQ_CAP reject drain, enqueue the scan moves it to X again denied again dispatch syncs ecaps, sub_ecaps_updated(X) Every highpri move to X in that window is denied and bounced. The two callbacks are meant to split the roles: ops.sub_caps_updated() tracks what the node holds and drives what it delegates to its children, while ops.sub_ecaps_updated() says whether a task can run on a cpu now. qmap used the first for both. Track the caps in effect from ops.sub_ecaps_updated() as avail_cids and place only on self_cids & avail_cids, so that self_cids stays the delegation split and avail_cids gates the placement. The stranded tests keep self_cids, as they ask whether the split gives the task anywhere at all. A highpri task whose self_cids lack caps in effect waits for them instead of being moved and bounced. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
8 dayssched_ext: scx_qmap: Do not add IMMED to rescue insertsTejun Heo
qmap's stranded fallback forces a task that can run on none of its self cids onto its first allowed cid with SCX_ENQ_RESCUE, and adds SCX_ENQ_IMMED when that cid is a time-share it holds. On such a cid the insert stops being a rescue request: 1. A task is enqueued while none of its allowed cids is in self_cids. At attach self_cids is still empty. 2. qmap inserts it into cid 0's local DSQ with SCX_ENQ_RESCUE | SCX_ENQ_IMMED. 3. The kernel finds ENQ_IMMED held on cid 0, admits the insert and skips the rescue diversion. 4. cid 0's cpu is busy, so the IMMED task is bounced back to qmap with SCX_ENQ_REENQ. 5. qmap's enqueue sees the same inputs and repeats step 2. Nothing runs in between. 6. The reenqueue limit ejects qmap with SCX_EXIT_ERROR_REENQ. The caps granted during the parent's ops.sub_attach() are delivered after the sub already holds its tasks, while the per-cid effective caps that mark the time-shares are delivered from the first dispatch after bypass lifts, so every attach that receives a time-share on a task's first allowed cid starts the loop. Drop IMMED from the rescue inserts so that step 3 diverts to the rescue path. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
12 dayssched_ext/scx_flatcg: Make cgv_node_less() wraparound-safeTao Cui
cgv_node_less() compares cvtimes with a plain <, which misorders once cvtime wraps: the wrapped node lands at the front of the tree while the unwrapped ones get stuck behind it. Each CPU picking a cgroup charges it a full slice, making wrap occur earlier than a naive estimate might suggest. Use time_before() instead. cgrp_cap_budget() bounds the lag behind cvtime_now, while the lead is bounded by the slice charge plus pending cvtime_delta on re-insertion, so the cyclic ordering assumptions of time_before() hold. Fixes: a4103eacc2ab ("sched_ext: Add a cgroup scheduler which uses flattened hierarchy") Reported-by: Sashiko <sashiko-bot@kernel.org> Link: https://lore.kernel.org/r/3f1ce004-e259-4e72-a5f7-14a5050053bd@linux.dev Signed-off-by: Tao Cui <cuitao@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
14 dayssched_ext: Check bpf_timer_start return values in scx_qmapWanwu Li
monitor_timerfn(), lowpri_timerfn() and round_robin_timerfn() ignore bpf_timer_start()'s return value: a failed re-arm silently stops the periodic heartbeat, starving every task parked in LOWPRI_DSQ (lowpri) or freezing cid rotation (round-robin). Check the returns and raise scx_bpf_error(), matching the init paths. Signed-off-by: Wanwu Li <liwanwu@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
14 dayssched_ext: Fix vtime delta loss in scx_flatcg cgroup migrationWanwu Li
fcg_cgroup_move() lost the signed vtime offset across cgroup migration in the mechanical conversion to time helpers: time_delta() clamps negative deltas to 0, so a queued task (whose dsq_vtime is normally behind the source frontier) loses its accumulated vtime credit and lands exactly at the destination frontier instead of keeping its relative position. Restore the wrapping signed subtraction. Fixes: 62addc6dbf36 ("sched_ext: Use time helpers in BPF schedulers") Signed-off-by: Wanwu Li <liwanwu@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
14 dayssched_ext: Fix timer pinning and return value in scx_centralWanwu Li
central_timerfn() re-arms the timer with a hardcoded BPF_F_TIMER_CPU_PIN flag and ignores the return value, defeating start_central_timer()'s -EINVAL fallback for kernels without the flag (<6.7): on such kernels the first tick kills the timer permanently with no diagnostic. Honor timer_pinned and check the return like the initial arm does. Fixes: 22a920209ab6 ("sched_ext: Implement tickless support") Signed-off-by: Wanwu Li <liwanwu@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-21sched_ext: Sync common and compat headers from the scx repoTejun Heo
Sync common.bpf.h, compat.bpf.h and compat.h with the scx repo, which accumulated the following: - __COMPAT_read_enum() can now recover 64-bit scx enum values from kernel BTF generated without BTF_KIND_ENUM64 support (pahole < 1.24 or --skip_encoding_btf_enum64, e.g. COS/GKE kernels), substituting values from the build-time vmlinux.h cross-checked against the low 32 bits the kernel does provide. - is_migration_disabled() no longer assumes the BPF prolog always disables migration. Since 8e4f0b1ebcf2 ("bpf: use rcu_read_lock_dont_migrate() for trampoline.c") the prolog only does so under CONFIG_PREEMPT_RCU, so the old current-task test under-reported on v6.18+ !PREEMPT_RCU kernels. A runtime probe on bpf_scx_reg() handles older kernels with backported trampoline behavior. - __COMPAT_scx_bpf_dsq_peek() is gated behind kernel v7.1 where 2f2ea7709266 ("sched_ext: Use dsq->first_task instead of list_empty() in dispatch_enqueue() FIFO-tail") fixed the kfunc spuriously returning NULL on non-empty FIFO DSQs, and the new scx_bpf_reenqueue_local_from_anywhere() provides a callable-from-anywhere reenqueue which prefers the generic scx_bpf_dsq_reenq(). Both were first posted by Gavin Guo and Changwoo Min and are picked up here with the review feedback folded in. - __COMPAT_scx_bpf_cpu_curr() and the scx_bpf_cpu_rq() declaration are restored. Schedulers built from these headers still run on pre-v6.18 kernels where scx_bpf_cpu_curr() does not resolve and the scx_bpf_cpu_rq() fallback still exists. - scx_clock_task() and scx_clock_pelt() document their stale-read behavior for remote idle CPUs under NO_HZ_IDLE. Link: https://lore.kernel.org/all/20260817143126.562923-1-changwoo@igalia.com Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-21sched_ext: Sync tools autogen enum headers from the scx repoTejun Heo
Regenerate enum_defs.autogen.h against the current tree, picking up the dispatch verdict enums and dropping the marker for the removed SCX_RQ_IN_BALANCE. Add enums_abi.autogen.h, a table of 64-bit scx enumerator values generated from vmlinux.h, used as the substitution source when the running kernel's BTF truncates 64-bit enum values to 32 bits. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-17sched_ext: Merge branch 'for-7.3-arena-args' into for-7.3Tejun Heo
Pull to receive the __arena argument conversion: 67f1f4a48c24 ("sched_ext: Pass kernel arena pointers to ops_cid callbacks") a8dc810968af ("sched_ext: Convert sub-cap kfuncs to __arena cmask arguments") a05c5b5cb5cf ("sched_ext: Convert scx_bpf_cid_override() to __arena array arguments") along with the bpf-next branch carrying the __arena argument support they depend on. Conflict in kernel/sched/ext/ext.c between: c384ab8a0b13 ("sched_ext: Move the config-off sub-cap kfunc stubs into sub.c") and: a8dc810968af ("sched_ext: Convert sub-cap kfuncs to __arena cmask arguments") which updated the stubs in their old ext.c location. Resolved by keeping ext.c without the stubs and applying the prototype conversion to the relocated stubs in sub.c. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-15sched_ext: Make core-sched task ordering hierarchy-awareTejun Heo
With sub-schedulers, tasks of different schedulers routinely share rqs and SMT siblings, but scx_prio_less() consults ops.core_sched_before() only when both tasks belong to the same scheduler. Every pair spanning two schedulers falls back to the default ordering, so no scheduler can express ordering across a scheduler boundary, including a root over its sub-schedulers' tasks. Order a pair spanning schedulers by the nearest common ancestor that implements ops.core_sched_before(): both tasks are in its subtree, making this the one op where a scheduler is called on tasks it delegated to its sub-schedulers and may not be scheduling anymore. Same-scheduler pairs keep using the owning scheduler's op so a parent never orders inside a subtree it delegated. The op is skipped when the deciding scheduler is bypassing on either task's CPU. Update scx_qmap to fall back to the kernel's default ordering when handed a delegated task it has no task_ctx for. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-15sched_ext: Fix inverted ops.core_sched_before() invocationTejun Heo
scx_prio_less() implements prio_less() semantics - %true means that @a is the lower priority and should run after @b. ops.core_sched_before() is documented to return %true when @a should run before @b. scx_prio_less() returns the op's value as-is, inverting the documented semantics at runtime. Call the op with the arguments swapped. scx_qmap followed the wiring instead of the documentation and returned %true for the younger task, so the two inversions canceled out and it behaved as intended. Flip its comparison to match. scx_qmap is likely the only current user in or out of the kernel tree. Any scheduler written the same way needs the same flip, while schedulers following the documentation are fixed by this change. Fixes: 7b0888b7cc19 ("sched_ext: Implement core-sched support") Cc: stable@vger.kernel.org # v6.12+ Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-15sched_ext: Rename balance-era identifiers to dispatch termsTejun Heo
sched_class->balance() is gone from sched_ext and what balance_one() does is run dispatch to produce something pickable. Update the balance-era names to dispatch terms: - balance_one() -> dispatch_one() - SCX_RQ_IN_BALANCE -> SCX_RQ_IN_DISPATCH No BPF scheduler reads the flag. The enum autogen headers gain the new name with the old entry retained like other removed enumerators, zero-filling at load time. No functional changes. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-14sched_ext/scx_flatcg: Fix cvtime true-up on slice expiryTao Cui
fcg_dispatch() true-ups the current cgroup's cvtime when its slice expires or its DSQ runs empty while the slice is still active: __sync_fetch_and_add(&cgc->cvtime_delta, (cpuc->cur_at + cgrp_slice_ns - now) * FCG_HWEIGHT_ONE / (cgc->hweight ?: 1)); The true-up should be actual minus charged: on CNS_EXPIRE, the overrun (now - cur_at - cgrp_slice_ns) should be added; on CNS_EMPTY, the unused portion of the slice should be subtracted. The expression above has the sign inverted, and in the CNS_EXPIRE case now is already past cur_at + cgrp_slice_ns, so the u64 subtraction wraps. The multiplication preserves the two's complement encoding but the unsigned division by hweight destroys it, adding roughly 2^64/hweight per expiry instead of a small correction. Under saturation the hweight budget clamp in cgrp_cap_budget() masks most of the garbage, so the weight distribution barely moves, but the accounting is broken all the same. Compute the delta as a signed value and use fetch_and_add()/fetch_and_sub() so that the dividends stay positive, as BPF division is unsigned. Instrumented the true-up and ran a saturated three-leaf cgroup tree on a 4-CPU VM: without the fix, each expiry added ~5e15 (2^64/hweight territory) to cvtime_delta; with it, the corrections are back to slice scale, with the overrun added and the unused portion subtracted. Fixes: a4103eacc2ab ("sched_ext: Add a cgroup scheduler which uses flattened hierarchy") Suggested-by: Tejun Heo <tj@kernel.org> Signed-off-by: Tao Cui <cuitao@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-14sched_ext: Fix scx_bpf_dsq_move_to_local___v2 compat detectionfangqiurong
libbpf strips the last ___flavor suffix when resolving kfunc externs, so the bare ___v2 declaration resolves to scx_bpf_dsq_move_to_local, whose BTF proto lacks @enq_flags. The extern never matches, bpf_ksym_exists() returns false on every kernel that has the ___v2 kfunc, and the macro falls back to ___v1, silently dropping @enq_flags. Add the trailing ___compat suffix used by the other versioned externs in this file (scx_bpf_dsq_insert___v2, scx_bpf_reenqueue_local___v2). Any caller passing non-zero @enq_flags through the compat macro silently loses them. Fixes: 860683763ebf ("sched_ext: Add enq_flags to scx_bpf_dsq_move_to_local()") Cc: stable@vger.kernel.org # v7.1+ Assisted-by: Z.ai:glm-5.2 Signed-off-by: fangqiurong <fangqiurong@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-14sched_ext: Fix scx_bpf_dsq_reenq___compat kfunc extern prototypeTejun Heo
scx_bpf_dsq_reenq() is registered with KF_IMPLICIT_ARGS and its kernel BTF prototype omits the trailing bpf_prog_aux argument. The ___compat extern declares the argument explicitly, so libbpf never matches the prototype and the weak extern silently stays unresolved on every kernel. The wrapper always takes the old fallback path, which disables generic reenq users like scx_qmap's lowpri mechanism and fails non-local reenq with "kernel too old" even on kernels that have the kfunc. Drop the explicit aux argument. Also correct the stale v6.20 reference, the kfunc was added in v7.1. Fixes: 9c34c5074d1b ("sched_ext: Introduce scx_bpf_dsq_reenq() for remote local DSQ reenqueue") Cc: stable@vger.kernel.org # v7.1+ Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-14sched_ext/scx_flatcg: expire cached hweights on weight changesTao Cui
fcg_cgroup_set_weight() updates cgc->weight and the parent's child_weight_sum but doesn't bump hweight_gen, so the hweights cached by cgrp_refresh_hweight() stay stale until some task activation bumps the generation. For cgroups whose tasks never go through a 0->n runnable transition (e.g. persistently busy ones), a cpu.weight change never propagates to scheduling at all. Bump hweight_gen on weight changes so the next refresh recomputes with the new weight. Verified on a flatcg VM: a live cpu.weight 100->800 change on a busy cgroup leaves HWT update at 0 and the distribution unchanged; with it, hweight_gen increments and the refresh recomputes. Signed-off-by: Tao Cui <cuitao@kylinos.cn> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-12sched_ext: Convert scx_bpf_cid_override() to __arena array argumentsTejun Heo
scx_bpf_cid_override() predates the cid-form arena transition and takes its arrays as verifier-checked mem+size buffers, forcing scx_qmap to keep the cpu_to_cid and shard_start arrays in writable bss while the rest of its state lives in the arena. Unify on arena arguments before cid-form schedulers start seeing real use. BPF now translates between BPF and kernel arena addresses for __arena arguments. Take the arrays as __arena arguments, with the counts passed in entries. The counts now size the snapshot copies and are bounds-checked before them. scx_qmap moves the arrays into struct qmap_arena. As the arena is mmapped at load, the loader populates them between load and attach instead of before load. The arena argument address translation is currently implemented only on x86-64. Schedulers calling this kfunc load only there for now. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-12sched_ext: Convert sub-cap kfuncs to __arena cmask argumentsTejun Heo
The sub-cap kfuncs take their cmask arguments as __ign pointers. The values cross the kfunc boundary as unchecked scalars and scx_cmask_ref_init() rebases them into the arena by hand. BPF now translates between BPF and kernel arena addresses for __arena arguments. Tag the cmask arguments __arena so the kfuncs receive kernel addresses and scx_cmask_ref_init() loses the hand-rolled conversion. The optional denied_out keeps its NULL not-provided signal via __arena__nullable. The mandatory masks use plain __arena. scx_qmap's call sites drop the (void *)(long) casts since the BPF-side declarations type the cmask arguments __arena and take arena pointers directly. The arena argument address translation is currently implemented only on x86-64. Schedulers calling these kfuncs load only there for now. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-12Merge branch 'for-7.3' into for-7.3-arena-argsTejun Heo
2026-08-12sched_ext: Merge branch 'for-7.2-fixes' into for-7.3Tejun Heo
Pull to receive: c10b216a072f ("sched/core: Handle pick_task() releasing the rq lock") f3629c63a4af ("sched/core: Make core-sched flips wait for in-flight selections") ffaab58d2175 ("sched_ext: Replace SCX_RQ_BAL_KEEP with a dispatch verdict return") 3dd52416e44a ("sched_ext: Fix this_rq() assumptions in dispatch kfuncs") f2da9587118d ("sched_ext: Count rq lock releases in rq->scx.lock_drop_seq") d954004205c1 ("sched_ext: Fix rq->core_pick corruption under core scheduling") for the pending core scheduling follow-ups and to resolve the conflicts with the code reorganization and cap gate work on for-7.3. ffaab58d2175 converts scx_dispatch_sched() to a dispatch verdict return which for-7.3 moved from ext.c into inlines.h. Resolved by applying the conversion to the relocated copy and combining balance_one()'s verdict returns with the scx_task_can_stay_on_cpu() gate from the cap work. ffaab58d2175 and 3dd52416e44a update scx_bpf_sub_dispatch() which for-7.3 moved into sub.c. Resolved by applying the scx_locked_rq() switch and the verdict test to the sub.c copy. f2da9587118d instruments the open-coded lock releases in consume_remote_task() which for-7.3 folded into switch_rq_lock(). Resolved by keeping the accounting in switch_rq_lock() which covers all its callers. d954004205c1 widens the put_prev_task_scx() WARN suppression to all core-sched rqs on the same condition that for-7.3 gated with scx_task_can_stay_on_cpu(). Resolved by combining both. Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-11sched_ext: Replace SCX_RQ_BAL_KEEP with a dispatch verdict returnTejun Heo
SCX_RQ_BAL_KEEP tells the pick to keep running the previous task, a leftover from when balancing and picking were separate operations. An rq-level flag only works while dispatches and picks pair up one to one, which core scheduling breaks: selections interleave through dispatch's lock drops and a pick can consume a stale flag, keeping a task that has since been dequeued. Fixing core scheduling support requires the decision to travel with the dispatch that made it. Make scx_dispatch_sched() and balance_one() return an explicit verdict instead and drop the flag's plumbing from the tools autogen enum headers. Also factor the pick-side invocation, its follow-up queueing and the post-dispatch checks out of do_pick_task_scx() into dispatch_pick(). No functional changes intended. v2: Drop the SCX_RQ_BAL_KEEP plumbing from the tools autogen enum headers as well (Andrea). Fixes: 4c95380701f5 ("sched/ext: Fold balance_scx() into pick_task_scx()") Cc: stable@vger.kernel.org # v6.19+ Signed-off-by: Tejun Heo <tj@kernel.org>
2026-08-10Merge branch 'master' of ↵Tejun Heo
git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next into for-7.3-arena-args Pull bpf-next d114bb989367 ("Merge branch 'add-arena-argument-support-to-kfuncs-and-struct_ops'") to make the __arena and __arena__nullable kfunc and struct_ops argument suffixes available. The suffixed arguments will be used to convert sched_ext kfuncs and struct_ops callbacks that currently pass arena pointers as scalars and rebase them by hand.
2026-08-03sched_ext: scx_qmap - Add rescue supportTejun Heo
A sched holds only the cids its parent granted and nothing guarantees that they cover its tasks' affinities. A task that can run on none of them has nowhere to go and qmap stalls out: it force-inserts the task onto its first allowed cid, but the kernel bounces the insert back and the task parks in SHARED_DSQ, which is drained only on self cids it can't run on. Set SCX_ENQ_RESCUE on these inserts so the kernel diverts such tasks to its rescue path instead of bouncing them. The force-insert covers scheds with and without children and fires on re-enqueues, and the SHARED_DSQ scan on every dispatch rescues tasks stranded there - the enqueue-time check misses a task whose cids were lost while it was already queued. The wrong-cid fault injection carries the flag too and doubles as a deterministic rescue-traffic generator. -B and -q set the root-only rescue bandwidth and quantum ops knobs. -B 0 maps to SCX_RESCUE_DISABLE and turns rescue off kernel-side. Rescue inserts are counted and reported in the hier stats line. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-08-03sched_ext: scx_qmap - Idle-check pinned tasks before direct dispatchTejun Heo
pick_direct_dispatch_cid() sent a pinned task straight to its only cpu without an idle check. An insert onto a time-shared cid is forced IMMED, which may not wait on a busy cpu - the kernel bounces the task back to ops.enqueue(), the shortcut re-inserts it, and the loop runs into the reenqueue repeat limit. Run pinned tasks through the same idle test as everyone else and queue them when the cpu is busy. always_enq_immed forces IMMED on every local insert and already skipped the shortcut for the same reason. The check was the last reader of the always_enq_immed rodata mirror, so drop the variable. The -I option still sets SCX_OPS_ALWAYS_ENQ_IMMED. v2: Drop the now-unread always_enq_immed rodata mirror. (sashiko AI) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-08-03sched_ext: Sync tools autogen enum headersTejun Heo
Mechanical regeneration for the enumerators added by the slice write rework and the rescue machinery. BPF schedulers reference SCX_ENQ_RESCUE, the rest are enum_defs presence markers. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-08-03sched_ext: Add bandwidth-limited rescue execution for stranded tasksTejun Heo
A local DSQ insert lacking the needed caps is diverted to the reject DSQ and bounced back through ops.enqueue() so the scheduler can re-decide. That recovery assumes the scheduler has somewhere legal to send the task. When it doesn't, e.g. when the task's affinity is restricted to cids delegated away, the task starves until the stall watchdog ejects the scheduler. An exiting task is worse - it skips ops.enqueue() and the rejection becomes a self-requeuing cycle that burns the CPU until the watchdog fires. Add SCX_ENQ_RESCUE, a fallback modifier on local DSQ inserts. When the insert would be rejected for missing caps, the kernel takes over and runs the task on the target CPU without consulting the owning scheduler. The kernel sets the flag itself when enqueueing an exiting task. Rescue is a last-resort forward-progress backstop with a persistent disadvantage, not a way around cap enforcement. A per-CPU token bucket accrues rescue_bandwidth_ppt (default 2%) of CPU time and rescues run one at a time in arrival order. Each is granted a slice of the rescue_quantum_us (default 5ms) quantum divided across the waiters, waits at the tail of the local DSQ claiming no priority, and rejoins its scheduler as a fresh arrival once the slice is served. The schedulers keep their normal control over an admitted rescuee and may preempt or reslice it. Service is measured on CPU time actually received, so neither shortens the rescue. Prolonged denial escalates - the remaining slice turns into protected execution (SCX_TASK_PROTECTED) and the rescuee preempts the current task. Escalation is paced by the same bucket, and delivered service converges on the configured bandwidth no matter how aggressively the schedulers dispatch. Both knobs are root-only and SCX_RESCUE_DISABLE turns rescue off, making SCX_ENQ_RESCUE inserts reject as usual. v2: - Add SCX_OPS_OPEN() fix-ups for the new ops fields so cpu-form schedulers setting them still load on older kernels. (Andrea) Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-07-26tools/sched_ext/include: Regenerate enum_defs.autogen.hTejun Heo
Regenerate enum_defs.autogen.h from the current vmlinux.h to pick up the SCX enum changes accumulated since the last regeneration, including the SCX_REENQ_LOCAL_MAX_REPEAT to SCX_REENQ_MAX_REPEAT rename. Reported-by: Andrea Righi <arighi@nvidia.com> Link: https://lore.kernel.org/all/amZsEbZJdDgjstPF@gpd4/ Signed-off-by: Tejun Heo <tj@kernel.org>
2026-07-24sched_ext: Gate scx_bpf_cidperf_set() behind a new SCX_CAP_PERFTejun Heo
scx_bpf_cidperf_set() reaches cpufreq with no cap check, so any cid-form sub-sched can steer the frequency of any cid in its view, including ones it holds nothing on. Gate it behind a new SCX_CAP_PERF rather than SCX_CAP_BASE: hardware control is a separate axis from queue access - a parent may well delegate scheduling on a cid without handing over its frequency. PERF neither implies nor is implied by the other caps. The check runs under the target rq's lock, which ecaps updates are also folded under, so it is authoritative - a write can never land after a revoke has taken effect. Denials are counted in SCX_EV_SUB_CIDPERF_DENIED. The operation is synchronous and the outcome is reported to the caller: scx_bpf_cidperf_set() now returns 0 or -errno, -EACCES on denial. The cid-form interface is still under initial development, so the signature is changed in place without versioning. scx_qmap grants PERF alongside its existing cid grants so the cpuperf demo keeps working in sub-scheds. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-07-24tools/sched_ext: Don't restart over a pending exit requestTejun Heo
The tools restart when the kernel exits the scheduler with SCX_ECODE_ACT_RESTART. The restart decision doesn't consult exit_req, so an exit request arriving while the restart condition persists is ignored and the tool reloads in a tight loop. Test exit_req before restarting. scx_userland needs more: its main loop never watches the kernel-side exit and exit_req doubles as the stats printer's stop signal, set by the teardown and reset on each restart. Add the missing UEI_EXITED() test and give the printer its own stop flag so that exit_req only means an exit request and stays latched like in the other tools. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-07-22tools/sched_ext: scx_pair: Convert to sched_switch TPCheng-Yang Chou
ops.cpu_acquire/release() are deprecated in favor of tracking CPU preemption from a sched_switch tracepoint, see commit a3f5d4822253 ("sched_ext: Allow scx_bpf_reenqueue_local() to be called from anywhere"). Loading scx_pair currently emits a deprecation warning. Replace the pair_cpu_acquire/release() callbacks with a tp_btf/sched_switch program that edge-detects the same transitions the core used to deliver: a release when a running SCX task loses its CPU to a higher-priority class, and an acquire when the CPU switches back to an SCX task or idle while marked preempted. Tasks are classified by effective priority (p->prio) rather than by policy: rt_mutex_setprio() boosts a PI beneficiary into the rt/dl classes while leaving its policy untouched, so a policy test would both miss the release when a boosted task takes the CPU and fire a spurious acquire when a boosted task replaces a real rt task. A switch from idle straight to a higher-priority task is deliberately not treated as a release. The CPU was not running an SCX task, so there is nothing to drain, and kicking SCX_KICK_PREEMPT | SCX_KICK_WAIT on every rt wakeup would make the pair CPU wait out rt bursts it was never coupled to. The old callbacks behaved the same way, firing ops.cpu_release() only from switch_class() when an SCX task was put for a higher class. The tracepoint runs on every context switch in the system, so the common no-transition case is filtered before taking the pair-shared lock. This is safe because a CPU's own preempted_mask bit is only ever written by this tracepoint running on that CPU. sched_setscheduler() on a running task changes class in place without a context switch, so such transitions are only observed at the task's next switch. The old callbacks had the same blind spot in switch_class(), and try_dispatch() already bounds the resulting wait. Verified in virtme-ng with the script below. The scheduler must load without the deprecation warning, stay enabled through the rt churn and the idle soak (the watchdog would otherwise abort it with "runnable task stall"), keep its preemption counter advancing, and unregister cleanly at the end. A PI rt-mutex churn that repeatedly boosts SCX tasks into the rt class was exercised separately: #!/bin/bash # vng --verbose --cpus 8 -m 4G --user root -- ./verify.sh # FIFO harness: survives even if all SCHED_NORMAL tasks stall [ "${RT:-0}" = 1 ] || exec chrt -f 5 env RT=1 "$0" chrt -o 0 ./tools/sched_ext/build/bin/scx_pair & PAIR=$! sleep 3 for round in $(seq 10); do pids="" for i in 0 1 2 3; do # SCHED_FIFO churn chrt -f 10 bash -c \ 'e=$((SECONDS+1)); while [ $SECONDS -lt $e ]; do :; done' & pids="$pids $!" done for i in 0 1; do # SCHED_NORMAL load under scx chrt -o 0 bash -c \ 'n=0; while [ $n -lt 200000 ]; do n=$((n+1)); done' & pids="$pids $!" done wait $pids # explicit pids, not the scx_pair job done sleep 300 # idle soak kill -INT $PAIR # expect clean unregister in dmesg Signed-off-by: Cheng-Yang Chou <yphbchou0911@gmail.com> Reviewed-by: Andrea Righi <arighi@nvidia.com> Signed-off-by: Tejun Heo <tj@kernel.org>
2026-07-19sched_ext: Rename the cid-form cgroup ops to cpuctl_*Tejun Heo
Two unrelated things go by "cgroup" in the cid form. Sub-schedulers attach to cgroups, and the cgroup_*() ops deliver cpu controller events. While the ops names suggest cgroup2 hierarchy, they actually operate on the cpu controller. Rename them to cpuctl_* in struct sched_ext_ops_cid, which has no users outside scx_qmap yet. The cpu form is deployed ABI and keeps the old names. The layout is unchanged and the kernel keeps calling through the cpu-form union view. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-07-19tools/sched_ext: Add SCX_OPS_CID_OPEN for cid-form schedulersTejun Heo
SCX_OPS_OPEN() clears compat-gated ops fields which the running kernel lacks. The clears dereference cpu-form member names and compile for cid-form skeletons only because both ops structs currently name their cgroup ops identically, which an upcoming rename will end. No load-time fix-up can apply to a cid-form scheduler anyway as the cid form postdates every compat-gated op. Factor the skeleton open path out of SCX_OPS_OPEN() and add SCX_OPS_CID_OPEN() which uses only that shared part. Switch scx_qmap, the only cid-form scheduler, over. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-07-19tools/sched_ext: scx_qmap - Add init fault injection modesTejun Heo
Add -J init-fail which makes ops.init_task() fail with -ENOMEM for tasks whose comm starts with "qmfail", and -J cgrp-init-fail which does the same in ops.cgroup_init() for cgroups named "qmfail*". The former exercises the migration veto path: the cgroup.procs write must fail with the injected errno while the destination sched stays up and the task stays put. The latter exercises the ownership-return failure path: a parent failing to re-init a returned cgroup leaves it unowned, and moves and set_* ops against it must be skipped instead of dereferencing the missing owner. Matching on "qmfail" names keeps the injecting scheduler's own enable unaffected. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-07-19tools/sched_ext: scx_qmap - Consume cgroup weights through set_weightTejun Heo
With the set_* ops delivered to the parent's sched, a parent qmap instance now receives cgroup_set_weight for its child subs' attach points. Update the matching sub_sched_ctx weight and redistribute() in-kernel, and drop the userspace feed_weights() polling. This exercises the knob routing end to end. The self weight is fixed at 100: a cgroup's weight is its parent's knob and not the scheduler's own business. This drops the self-weight polling and the repartition PROG_RUN poke with it. sub_attach seeds the slot with the cgroup's current weight, read through bpf_cgroup_from_id(), so a weight set before the sub attaches is picked up. A write racing the attach can still be lost until the next value-changing cpu.weight write. Acceptable for a demo. While at it, add a traced ops.cgroup_move() so tests can observe move delivery. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
2026-07-17Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf 7.2-rc4Kumar Kartikeya Dwivedi
Cross-merge BPF and other fixes after downstream PR. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
2026-07-14tools/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>
2026-07-13tools/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>
2026-07-13tools/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>
2026-07-13tools/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>
2026-07-13sched_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>