From: Tejun Heo <tj@kernel.org>
To: David Vernet <void@manifault.com>,
Andrea Righi <arighi@nvidia.com>,
Changwoo Min <changwoo@igalia.com>
Cc: sched-ext@lists.linux.dev, Emil Tsalapatis <emil@etsalapatis.com>,
linux-kernel@vger.kernel.org, Tejun Heo <tj@kernel.org>
Subject: [PATCH v2 sched_ext/for-7.3 31/36] sched_ext: Authorize remote-move inserts against the placing scheduler
Date: Sun, 5 Jul 2026 15:40:53 -1000 [thread overview]
Message-ID: <20260706014058.439853-32-tj@kernel.org> (raw)
In-Reply-To: <20260706014058.439853-1-tj@kernel.org>
scx_local_or_reject_dsq() authorizes a local-DSQ insert against the caps
of the scheduler doing the insert. On the consume/dispatch paths that is
the scheduler running balance_one(), passed down through
scx_consume_dispatch_q() and move_local_task_to_local_dsq(), so the check
is correct.
The remote-move path loses it. move_remote_task_to_local_dsq()
re-activates @p on the destination rq through enqueue_task_scx(), which
reconstructs the scheduler from the task, i.e. @p's owner. When an
ancestor places a descendant's task - e.g. draining a bypassed
sub-scheduler - the owner is a sub-scheduler of the placer, so
authorizing against the owner checks a narrower cap set and can
spuriously reject a task the placer is entitled to run.
Carry the placing scheduler across the activate_task() boundary the same
way enq_flags already are, via a per-rq field set only for the duration
of the re-activation, and have scx_local_or_reject_dsq() authorize
against it. The placer's caps are a superset of the owner's, so this
admits what the placer may run and keeps rejecting what it may not.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
kernel/sched/ext/ext.c | 27 +++++++++++++++------------
kernel/sched/ext/sub.c | 9 +++++++--
kernel/sched/sched.h | 3 ++-
3 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index 1c1b58a66f94..46ba905c96e2 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -2238,7 +2238,8 @@ static void move_local_task_to_local_dsq(struct scx_sched *sch,
*
* Move @p which is currently on @src_rq to @dst_rq's local DSQ.
*/
-static void move_remote_task_to_local_dsq(struct task_struct *p, u64 enq_flags,
+static void move_remote_task_to_local_dsq(struct scx_sched *sch,
+ struct task_struct *p, u64 enq_flags,
struct rq *src_rq, struct rq *dst_rq)
{
lockdep_assert_rq_held(src_rq);
@@ -2255,15 +2256,19 @@ static void move_remote_task_to_local_dsq(struct task_struct *p, u64 enq_flags,
raw_spin_rq_lock(dst_rq);
/*
- * We want to pass scx-specific enq_flags but activate_task() will
- * truncate the upper 32 bit. As we own @rq, we can pass them through
- * @rq->scx.remote_activate_enq_flags instead.
+ * activate_task() below truncates enq_flags to 32 bits and re-derives
+ * @p's owner, dropping our scx flags and the placing @sch. We own @rq,
+ * so stash both across the call. The enqueue reads them back, keeping
+ * the scx flags and checking caps against the placer, not the owner.
*/
WARN_ON_ONCE(!cpumask_test_cpu(cpu_of(dst_rq), p->cpus_ptr));
- WARN_ON_ONCE(dst_rq->scx.remote_activate_enq_flags);
+ WARN_ON_ONCE(dst_rq->scx.remote_activate_enq_flags ||
+ dst_rq->scx.remote_activate_sch);
dst_rq->scx.remote_activate_enq_flags = enq_flags;
+ dst_rq->scx.remote_activate_sch = sch;
activate_task(dst_rq, p, 0);
dst_rq->scx.remote_activate_enq_flags = 0;
+ dst_rq->scx.remote_activate_sch = NULL;
}
/*
@@ -2392,14 +2397,14 @@ static bool unlink_dsq_and_lock_src_rq(struct task_struct *p,
!WARN_ON_ONCE(src_rq != task_rq(p));
}
-static bool consume_remote_task(struct rq *this_rq,
+static bool consume_remote_task(struct scx_sched *sch, struct rq *this_rq,
struct task_struct *p, u64 enq_flags,
struct scx_dispatch_q *dsq, struct rq *src_rq)
{
raw_spin_rq_unlock(this_rq);
if (unlink_dsq_and_lock_src_rq(p, dsq, src_rq)) {
- move_remote_task_to_local_dsq(p, enq_flags, src_rq, this_rq);
+ move_remote_task_to_local_dsq(sch, p, enq_flags, src_rq, this_rq);
return true;
} else {
raw_spin_rq_unlock(src_rq);
@@ -2461,8 +2466,7 @@ static struct rq *move_task_between_dsqs(struct scx_sched *sch,
raw_spin_unlock(&src_dsq->lock);
} else {
raw_spin_unlock(&src_dsq->lock);
- move_remote_task_to_local_dsq(p, enq_flags,
- src_rq, dst_rq);
+ move_remote_task_to_local_dsq(sch, p, enq_flags, src_rq, dst_rq);
}
} else {
/*
@@ -2515,7 +2519,7 @@ bool scx_consume_dispatch_q(struct scx_sched *sch, struct rq *rq,
}
if (task_can_run_on_remote_rq(sch, p, rq, false)) {
- if (likely(consume_remote_task(rq, p, enq_flags, dsq, task_rq)))
+ if (likely(consume_remote_task(sch, rq, p, enq_flags, dsq, task_rq)))
return true;
goto retry;
}
@@ -2609,8 +2613,7 @@ static void dispatch_to_local_dsq(struct scx_sched *sch, struct rq *rq,
scx_dispatch_enqueue(sch, src_rq, find_global_dsq(sch, task_cpu(p)),
p, enq_flags | SCX_ENQ_GDSQ_FALLBACK);
} else {
- move_remote_task_to_local_dsq(p, enq_flags,
- src_rq, dst_rq);
+ move_remote_task_to_local_dsq(sch, p, enq_flags, src_rq, dst_rq);
/* task has been moved to dst_rq, which is now locked */
locked_rq = dst_rq;
}
diff --git a/kernel/sched/ext/sub.c b/kernel/sched/ext/sub.c
index d99106da6ea9..d23c1e3e8dfa 100644
--- a/kernel/sched/ext/sub.c
+++ b/kernel/sched/ext/sub.c
@@ -229,12 +229,17 @@ struct scx_dispatch_q *scx_local_or_reject_dsq(struct scx_sched *sch, struct rq
struct task_struct *p, u64 *enq_flags)
{
s32 cid = __scx_cpu_to_cid(cpu_of(rq));
+ struct scx_sched *asch = rq->scx.remote_activate_sch ?: sch;
u64 needed = scx_caps_for_enq(*enq_flags);
u64 missing;
+ /*
+ * On a remote activation the scheduling sched (@asch) differs from
+ * @p's owner (@sch). Check caps against the scheduling sched.
+ */
if (*enq_flags & SCX_ENQ_PREEMPT)
- needed |= scx_caps_for_preempt(sch, rq);
- missing = scx_missing_caps(sch, cpu_of(rq), needed);
+ needed |= scx_caps_for_preempt(asch, rq);
+ missing = scx_missing_caps(asch, cpu_of(rq), needed);
/* requirements met */
if (likely(!missing))
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index c0a4699a6c0a..cdd21c814008 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -800,8 +800,9 @@ struct scx_rq {
struct list_head runnable_list; /* runnable tasks on this rq */
struct list_head ddsp_deferred_locals; /* deferred ddsps from enq */
unsigned long ops_qseq;
- /* see move_remote_task_to_local_dsq() */
+ /* both stashed across the activate_task() in move_remote_task_to_local_dsq() */
u64 remote_activate_enq_flags;
+ struct scx_sched *remote_activate_sch;
u32 nr_running;
u32 cpuperf_target; /* [0, SCHED_CAPACITY_SCALE] */
bool in_select_cpu;
--
2.54.0
next prev parent reply other threads:[~2026-07-06 1:41 UTC|newest]
Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 1:40 [PATCHSET v2 sched_ext/for-7.3] sched_ext: Capability-based CPU delegation for sub-schedulers Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 01/36] sched_ext: Add SCX_CALL_CID_OP_TASK() for cid-form op dispatch Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 02/36] sched_ext: Rename extra_enq_flags to remote_activate_enq_flags Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 03/36] sched_ext: Fix premature ops->priv publication in scx_alloc_and_add_sched() Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 04/36] tools/sched_ext: scx - Fix cmask_subset(), cmask_equal() and cmask_weight() Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 05/36] sched_ext: Use READ_ONCE/WRITE_ONCE in cmask word ops and drop _RACY variants Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 06/36] tools/sched_ext: scx_qmap - Use bare u64/u32/s32 integer types Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 07/36] sched_ext: Reject direct slice and dsq_vtime writes for cid-form schedulers Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 08/36] sched_ext: Make scx_bpf_kick_cid() return void Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 09/36] sched_ext: Make the kick machinery per-sched Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 10/36] sched_ext: Add ops.init_cids() to finalize the cid layout before init Tejun Heo
2026-07-06 2:08 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 11/36] sched_ext: Add CID sharding Tejun Heo
2026-07-06 1:53 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 12/36] sched_ext: Add shard boundaries to scx_bpf_cid_override() Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 13/36] sched_ext: Defer scx_sched kobj sysfs add into the enable workfns Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 14/36] sched_ext: Add per-shard scx_sched storage scaffolding Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 15/36] sched_ext: Add scx_cmask_ref for validated arena cmask access Tejun Heo
2026-07-06 1:58 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 9:04 ` Andrea Righi
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 16/36] sched_ext: Build the set_cmask scratch from trusted geometry Tejun Heo
2026-07-06 1:59 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 17/36] sched_ext: RCU-protect the sub-sched tree's children/sibling lists Tejun Heo
2026-07-06 2:08 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 18/36] sched_ext: Add scx_skip_subtree_pre() Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 19/36] sched_ext: Add per-shard cap delegation for sub-schedulers Tejun Heo
2026-07-06 2:13 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 20/36] sched_ext: Add coalescing sub_caps_updated() notifier " Tejun Heo
2026-07-06 2:06 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 21/36] sched_ext: Maintain per-cpu effective cap copies for single-read checks Tejun Heo
2026-07-06 2:07 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 22/36] sched_ext: Add sub_ecaps_updated() effective-cap change notifier Tejun Heo
2026-07-06 2:09 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 23/36] sched_ext: Generalize local-DSQ handling to rq-owned DSQs Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 24/36] sched_ext: Add reject DSQ for cap-rejected dispatches Tejun Heo
2026-07-06 2:08 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 25/36] sched_ext: Add the SCX_CAP_ENQ_IMMED cap Tejun Heo
2026-07-06 2:10 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 26/36] sched_ext: Assign a unique id to each scheduler instance Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 27/36] sched_ext: Route task slice writes through set_task_slice() Tejun Heo
2026-07-06 2:05 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 9:10 ` Andrea Righi
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 28/36] sched_ext: Tie cpu occupancy to SCX_CAP_BASE through the task slice Tejun Heo
2026-07-06 2:07 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 29/36] sched_ext: Add the SCX_CAP_ENQ cap Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 30/36] sched_ext: Gate kicks on SCX_CAP_BASE and preemption on SCX_CAP_PREEMPT Tejun Heo
2026-07-06 1:40 ` Tejun Heo [this message]
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 32/36] sched_ext: Route ops.update_idle() to sub-schedulers and re-notify owed scheds Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 33/36] sched_ext: Replay ecaps notifications suppressed by bypass Tejun Heo
2026-07-06 2:11 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 34/36] sched_ext: Add scx_bpf_sub_kill() to evict a child sub-scheduler Tejun Heo
2026-07-06 2:12 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 35/36] tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling Tejun Heo
2026-07-06 2:10 ` sashiko-bot
2026-07-06 23:40 ` Tejun Heo
2026-07-06 1:40 ` [PATCH v2 sched_ext/for-7.3 36/36] tools/sched_ext: scx_qmap - Add sub-sched cap fault injection 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=20260706014058.439853-32-tj@kernel.org \
--to=tj@kernel.org \
--cc=arighi@nvidia.com \
--cc=changwoo@igalia.com \
--cc=emil@etsalapatis.com \
--cc=linux-kernel@vger.kernel.org \
--cc=sched-ext@lists.linux.dev \
--cc=void@manifault.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.