From: Andrea Righi <arighi@nvidia.com>
To: Tejun Heo <tj@kernel.org>
Cc: David Vernet <void@manifault.com>,
Changwoo Min <changwoo@igalia.com>,
sched-ext@lists.linux.dev, Emil Tsalapatis <emil@etsalapatis.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCHSET v5 sched_ext/for-7.3] sched_ext: Capability-based CPU delegation for sub-schedulers
Date: Tue, 14 Jul 2026 09:10:13 +0200 [thread overview]
Message-ID: <alXg1Ux83csDVjKf@gpd4> (raw)
In-Reply-To: <20260709225041.1695495-1-tj@kernel.org>
Hi Tejun,
On Thu, Jul 09, 2026 at 12:50:08PM -1000, Tejun Heo wrote:
> Hello,
>
> Changes in v5:
I went through the series and tested the resulting kernel under virtme-ng. I
couldn't trigger any crashes, lockups, or warnings, and I don't see any issues
that should block applying this.
As I mentioned, one possible follow-up optimization would be to introduce a
"scx_has_sub_scheds" static key, indicating whether any sub-scheduler is
attached. This could preserve the current fast paths for the common case of a
single root-only scheduler, avoiding the small potential overhead of
sub-scheduler-specific hierarchy walks and capability checks. And it could also
enable additional optimizations in the future.
For the series:
Reviewed-by: Andrea Righi <arighi@nvidia.com>
Thanks,
-Andrea
>
> - Patches 1-9 of v4 were applied to sched_ext/for-7.2-fixes and
> sched_ext/for-7.3 and are dropped. The series is rebased onto the
> updated for-7.3.
>
> - New patch (01): WARN when a per-task op is dispatched on a scheduler
> other than the task's owner, with the two intentional non-owner call
> sites dispatching explicitly. Hardening out of the v4 placer-vs-owner
> review discussion. (sashiko AI)
>
> - New prep patch (19): an in-place SAVE/RESTORE requeue of a running task
> re-ran cid admission and could bounce a task to the reject DSQ under a
> scheduler holding only SCX_CAP_ENQ_IMMED. Mark such enqueues with an
> internal IGNORE_CAPS flag which requires no caps. (sashiko AI)
>
> - The CONFIG_EXT_SUB_SCHED=n scx_prog_sched() stub now also refuses a
> dead root scheduler, matching the =y behavior (12). (sashiko AI)
>
> - scx_qmap: mask the highpri dispatch pick with the node's own cids and
> read the sub cgroup_id once in the dispatch path (32). (sashiko AI)
>
> v4: https://lore.kernel.org/r/20260708212429.3405787-1-tj@kernel.org
> v3: https://lore.kernel.org/r/20260707001229.1410929-1-tj@kernel.org
> v2: https://lore.kernel.org/r/20260706014058.439853-1-tj@kernel.org
> v1: https://lore.kernel.org/r/20260703080159.2314350-1-tj@kernel.org
>
> The existing sub-scheduler support only covers a part of scheduling. An
> scx_sched can attach to a cgroup subtree under another scx_sched and detach,
> and the dispatch path has programmatic delegation: dispatch runs as top-down
> recursion via scx_bpf_sub_dispatch(), so a parent decides when a child gets
> to pick tasks for the local cpu by calling into it.
>
> The enqueue path is not implemented yet. Every scheduler in the hierarchy
> can insert into every local DSQ, so a parent has no way to partition CPUs
> among its children or protect its own share from them.
>
> This patchset adds that control. Most importantly it enables sub-sched
> support on the enqueue path, and it extends the same control to the other
> paths that touch cpu access: occupancy, kicks and preemption, and idle
> reporting.
>
> The enqueue path cannot use the dispatch path's programmatic model.
> Dispatch is top-down and the delegation is implicit in the call chain.
> Enqueue starts at the other end: a leaf picks a cid for a task, and which
> cids it may use is the cumulative result of its ancestors' delegation
> decisions. Resolving that programmatically on every enqueue would mean a
> cross-sched round-trip call chain, possibly retrying when a request
> cannot be granted as-is. Delegation is therefore state, not calls:
>
> - Ownership is tracked per (scheduler, cid) as a set of capabilities:
>
> - SCX_CAP_ENQ_IMMED: insert an IMMED task onto the cid's local DSQ.
> This is the baseline cap (SCX_CAP_BASE) required to make any use of
> a cpu.
>
> - SCX_CAP_ENQ: insert any task onto the cid's local DSQ.
>
> - SCX_CAP_PREEMPT: preempt a task outside the scheduler's own subtree.
>
> Higher caps imply the lower ones for the holder's own use.
>
> - The root owns every cap on every cid. A parent delegates caps to a
> child with scx_bpf_sub_grant() and takes them back with
> scx_bpf_sub_revoke(). A child's cap set is always a subset of its
> parent's.
>
> - The cap state is sharded. The cid space is split into topology-aligned
> shards, and each scheduler tracks its caps in per-shard cmasks with a
> per-shard lock. Operations are broken up on shard boundaries and different
> shards never contend. Shards are expected to serve as the locality unit
> when cids are handed out to schedulers, so lock granularity scales
> naturally with the allocation pattern.
>
> - Hot paths check a per-cpu effective-caps copy with a single read.
> Grant/revoke rings a per-cpu doorbell and the owning cpu folds the new
> config in at the top of balance(). Cross-sched communication happens only
> when the delegation set changes.
>
> Enforcement:
>
> - An insert that lacks the required cap is diverted to a kernel-internal
> per-rq reject DSQ and handed back to the BPF scheduler to re-decide,
> tagged with SCX_TASK_REENQ_CAP and the missing caps.
>
> - A revoke evicts already-queued and running tasks through the same
> reenqueue path.
>
> - CPU occupancy is tied to the task slice. Extending a slice requires
> baseline access on the cpu.
>
> - Kicks are enforced at delivery. Any kick needs baseline access on the
> target cid, and SCX_KICK_PREEMPT degrades to a plain reschedule if the
> victim is outside the kicker's subtree and the kicker lacks
> SCX_CAP_PREEMPT.
>
> Notifications:
>
> - ops.sub_caps_updated() reports config-level changes per shard with
> coalescing.
>
> - ops.sub_ecaps_updated() reports per-cpu effective changes when they
> take effect.
>
> - ops.update_idle() is routed to the cid's owner, with a re-notification
> when ownership changes while the cpu sits idle.
>
> A parent can evict a misbehaving child with scx_bpf_sub_kill().
>
> To make it concrete, consider a root scheduler R with a child A, which
> in turn has a child A1:
>
> - On enable, R owns every cap on every cid. A child starts with no caps
> and cannot use any cpu on its own, so a parent normally makes an
> initial grant when a child attaches.
>
> - R grants cids 8-15 to A by calling scx_bpf_sub_grant() with A's cgroup
> id and a cmask. A grant is all-or-nothing per cid and can only hand
> down caps R holds literally.
>
> - A learns of the grant through ops.sub_caps_updated(). As each cpu
> folds the change into its effective caps, A gets
> ops.sub_ecaps_updated() for that cid, and if the cpu is sitting idle,
> an ops.update_idle() re-notification so A can use it right away.
>
> - Nesting chains through the same notifier: from its
> ops.sub_caps_updated(), A calls scx_bpf_sub_grant() to pass a subset, say
> cids 12-15, down to A1, whose own ops.sub_caps_updated() then fires. A1's
> cap set is a subset of A's, which is a subset of R's. Caps A holds only
> through implication cannot be re-delegated.
>
> Using and then losing a cpu, from A's point of view, looks like this:
>
> - Holding SCX_CAP_ENQ on cid 8, A inserts its tasks into cid 8's local
> DSQ from its enqueue and dispatch paths, extends their slices, and
> kicks the cpu as usual.
>
> - R revokes cid 8. The revoke clears it across A's whole subtree, so A1
> loses whatever it held on the cid too.
>
> - Once the revoke reaches the cpu's effective caps, A's tasks queued on
> cid 8 are handed back to A's ops.enqueue() tagged with
> SCX_TASK_REENQ_CAP and the missing caps, a running task is evicted by
> zeroing its slice, and new inserts are rejected and handed back the
> same way.
>
> - A places the bounced tasks somewhere it still holds, and the notifiers
> tell it that its holdings shrank.
>
> The final three patches expand the scx_qmap hierarchical demo: a qmap
> instance splits the cpus it fully owns among itself and child qmaps in
> proportion to cpu.weight, time-shares the rounding leftovers through a
> round-robin pool, and can fault-inject dispatches to unheld cids to
> demonstrate the kernel-side enforcement.
>
> Known limitations:
>
> After this series, sub-scheduling works as long as tasks stay within their
> cgroup boundary and aren't affined away from the cpus their scheduler can
> use. Two pieces are still missing for full support:
>
> - cgroup migration doesn't move a task across sub-schedulers. A task moved
> between cgroups served by different sub-scheds keeps its original
> scheduler.
>
> - there is no fallback when a sub-scheduler holds no cpu a task is allowed
> to run on. Such a task, e.g. one affined only to cids its scheduler was
> never granted or has had revoked, has nowhere to go. The likely
> direction is reserving a slice off the root scheduler to run tasks
> without cpu access.
>
> Based on sched_ext/for-7.3 (3d1519011e39).
>
> This patchset contains the following 33 patches.
>
> 0001 sched_ext: Assert per-task ops run on the task's owner
> 0002 sched_ext: Make the kick machinery per-sched
> 0003 sched_ext: Add ops.init_cids() to finalize the cid layout before init
> 0004 sched_ext: Add CID sharding
> 0005 sched_ext: Add shard boundaries to scx_bpf_cid_override()
> 0006 sched_ext: Defer scx_sched kobj sysfs add into the enable workfns
> 0007 sched_ext: Add per-shard scx_sched storage scaffolding
> 0008 sched_ext: Add scx_cmask_ref for validated arena cmask access
> 0009 sched_ext: Build the set_cmask scratch from trusted geometry
> 0010 sched_ext: RCU-protect the sub-sched tree's children/sibling lists
> 0011 sched_ext: Add scx_skip_subtree_pre()
> 0012 sched_ext: Stop resolving a disabled scheduler's programs
> 0013 sched_ext: Add per-shard cap delegation for sub-schedulers
> 0014 sched_ext: Add coalescing sub_caps_updated() notifier for sub-schedulers
> 0015 sched_ext: Maintain per-cpu effective cap copies for single-read checks
> 0016 sched_ext: Add sub_ecaps_updated() effective-cap change notifier
> 0017 sched_ext: Generalize local-DSQ handling to rq-owned DSQs
> 0018 sched_ext: Add reject DSQ for cap-rejected dispatches
> 0019 sched_ext: Add SCX_ENQ_IGNORE_CAPS for in-place restore
> 0020 sched_ext: Add the SCX_CAP_ENQ_IMMED cap
> 0021 sched_ext: Assign a unique id to each scheduler instance
> 0022 sched_ext: Route task slice writes through set_task_slice()
> 0023 sched_ext: Track the cpu a task is runnable on
> 0024 sched_ext: Tie cpu occupancy to SCX_CAP_BASE through the task slice
> 0025 sched_ext: Add the SCX_CAP_ENQ cap
> 0026 sched_ext: Gate kicks on SCX_CAP_BASE and preemption on SCX_CAP_PREEMPT
> 0027 sched_ext: Authorize remote-move inserts against the placing scheduler
> 0028 sched_ext: Route ops.update_idle() to sub-schedulers and re-notify owed scheds
> 0029 sched_ext: Replay ecaps notifications suppressed by bypass
> 0030 sched_ext: Add scx_bpf_sub_kill() to evict a child sub-scheduler
> 0031 tools/sched_ext: Add three-mask cmask intersection iterator
> 0032 tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling
> 0033 tools/sched_ext: scx_qmap - Add sub-sched cap fault injection
>
> The patches are organized as follows:
>
> - 01: prep. Assert per-task ops run on the task's owner.
>
> - 02-12: plumbing. Per-sched kick machinery (02), ops.init_cids() (03),
> cid sharding (04-05), sysfs and per-shard storage prep (06-07),
> validated arena cmask access (08) and the trusted-geometry set_cmask
> build (09), RCU-safe tree walking (10-11), and gating a disabled
> scheduler's still-resolvable programs (12).
>
> - 13-16: cap delegation. Per-shard caps with grant/revoke (13), the
> coalescing sub_caps_updated() notifier (14), per-cpu effective caps
> (15) and the sub_ecaps_updated() notifier (16).
>
> - 17-27: enforcement. The reject DSQ (17-18), the restore cap bypass
> (19), SCX_CAP_ENQ_IMMED (20), slice-based occupancy (21-24),
> SCX_CAP_ENQ (25), preemption and kick gating (26) and remote-move
> insert authorization (27).
>
> - 28-30: idle routing and re-notification (28), bypass replay (29) and
> scx_bpf_sub_kill() (30).
>
> - 31-33: scx_qmap hierarchical demo.
>
> The patchset is also available in the following git branch:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git scx-sub-caps-v5
>
> diffstat follows. Thanks.
>
> include/linux/sched/ext.h | 33 +-
> init/init_task.c | 1 +
> kernel/sched/ext/cid.c | 508 +++++++++++++-
> kernel/sched/ext/cid.h | 17 +-
> kernel/sched/ext/ext.c | 852 ++++++++++++++++++-----
> kernel/sched/ext/idle.c | 86 ++-
> kernel/sched/ext/internal.h | 334 ++++++++-
> kernel/sched/ext/sub.c | 1120 +++++++++++++++++++++++++++++-
> kernel/sched/ext/sub.h | 121 +++-
> kernel/sched/ext/types.h | 74 +-
> kernel/sched/idle.c | 8 +-
> kernel/sched/sched.h | 17 +-
> tools/sched_ext/include/scx/cid.bpf.h | 77 ++
> tools/sched_ext/include/scx/common.bpf.h | 24 +
> tools/sched_ext/include/scx/compat.bpf.h | 11 +-
> tools/sched_ext/scx_qmap.bpf.c | 852 ++++++++++++++++++++---
> tools/sched_ext/scx_qmap.c | 355 +++++++++-
> tools/sched_ext/scx_qmap.h | 115 ++-
> 18 files changed, 4238 insertions(+), 367 deletions(-)
>
> --
> tejun
next prev parent reply other threads:[~2026-07-14 7:10 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 22:50 [PATCHSET v5 sched_ext/for-7.3] sched_ext: Capability-based CPU delegation for sub-schedulers Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 01/33] sched_ext: Assert per-task ops run on the task's owner Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 02/33] sched_ext: Make the kick machinery per-sched Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 03/33] sched_ext: Add ops.init_cids() to finalize the cid layout before init Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 04/33] sched_ext: Add CID sharding Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 05/33] sched_ext: Add shard boundaries to scx_bpf_cid_override() Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 06/33] sched_ext: Defer scx_sched kobj sysfs add into the enable workfns Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 07/33] sched_ext: Add per-shard scx_sched storage scaffolding Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 08/33] sched_ext: Add scx_cmask_ref for validated arena cmask access Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 09/33] sched_ext: Build the set_cmask scratch from trusted geometry Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 10/33] sched_ext: RCU-protect the sub-sched tree's children/sibling lists Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 11/33] sched_ext: Add scx_skip_subtree_pre() Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 12/33] sched_ext: Stop resolving a disabled scheduler's programs Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 13/33] sched_ext: Add per-shard cap delegation for sub-schedulers Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 14/33] sched_ext: Add coalescing sub_caps_updated() notifier " Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 15/33] sched_ext: Maintain per-cpu effective cap copies for single-read checks Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 16/33] sched_ext: Add sub_ecaps_updated() effective-cap change notifier Tejun Heo
2026-07-14 6:00 ` Andrea Righi
2026-07-14 8:07 ` Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 17/33] sched_ext: Generalize local-DSQ handling to rq-owned DSQs Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 18/33] sched_ext: Add reject DSQ for cap-rejected dispatches Tejun Heo
2026-07-14 6:49 ` Andrea Righi
2026-07-14 8:08 ` Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 19/33] sched_ext: Add SCX_ENQ_IGNORE_CAPS for in-place restore Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 20/33] sched_ext: Add the SCX_CAP_ENQ_IMMED cap Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 21/33] sched_ext: Assign a unique id to each scheduler instance Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 22/33] sched_ext: Route task slice writes through set_task_slice() Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 23/33] sched_ext: Track the cpu a task is runnable on Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 24/33] sched_ext: Tie cpu occupancy to SCX_CAP_BASE through the task slice Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 25/33] sched_ext: Add the SCX_CAP_ENQ cap Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 26/33] sched_ext: Gate kicks on SCX_CAP_BASE and preemption on SCX_CAP_PREEMPT Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 27/33] sched_ext: Authorize remote-move inserts against the placing scheduler Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 28/33] sched_ext: Route ops.update_idle() to sub-schedulers and re-notify owed scheds Tejun Heo
2026-07-14 6:18 ` Andrea Righi
2026-07-14 8:08 ` Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 29/33] sched_ext: Replay ecaps notifications suppressed by bypass Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 30/33] sched_ext: Add scx_bpf_sub_kill() to evict a child sub-scheduler Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 31/33] tools/sched_ext: Add three-mask cmask intersection iterator Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 32/33] tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling Tejun Heo
2026-07-09 22:50 ` [PATCH v5 sched_ext/for-7.3 33/33] tools/sched_ext: scx_qmap - Add sub-sched cap fault injection Tejun Heo
2026-07-14 7:10 ` Andrea Righi [this message]
2026-07-14 8:07 ` [PATCHSET v5 sched_ext/for-7.3] sched_ext: Capability-based CPU delegation for sub-schedulers Tejun Heo
2026-07-14 8:27 ` 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=alXg1Ux83csDVjKf@gpd4 \
--to=arighi@nvidia.com \
--cc=changwoo@igalia.com \
--cc=emil@etsalapatis.com \
--cc=linux-kernel@vger.kernel.org \
--cc=sched-ext@lists.linux.dev \
--cc=tj@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox