diff options
| author | Tejun Heo <tj@kernel.org> | 2026-07-24 09:09:28 -1000 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2026-07-24 12:10:21 -1000 |
| commit | f879519db8a2f1b3922f9023daec1642f68df51d (patch) | |
| tree | 3e6a79080ea96b29180a5aab1d5acfcc37c63afa | |
| parent | 457daba18e209fefeb3b88b1a2868c70704950ba (diff) | |
| download | linux-f879519db8a2f1b3922f9023daec1642f68df51d.tar.gz linux-f879519db8a2f1b3922f9023daec1642f68df51d.zip | |
sched_ext: Gate local DSQ reenq on baseline cid access
scx_bpf_dsq_reenq() with an SCX_DSQ_LOCAL_ON target schedules deferred reenq
work on the cid's cpu, raising an IPI when the target rq isn't the locked
one. Nothing checks caps along the way, so a sub-sched holding no cap at all
on a cid can force its cpu to take IPIs and rq lock cycles at will. The
analogous scx_bpf_kick_cid() path gates delivery on SCX_CAP_BASE in
kick_one_cpu() to prevent exactly this.
Apply the same rule at the reenq scheduling point: if the calling sched
lacks SCX_CAP_BASE on the target cid, drop the reenq and count it in the new
SCX_EV_SUB_REENQ_DENIED event. The check is lockless, which is fine: a reenq
slipping through right after a revoke is harmless, and a wrong denial can't
happen - if the caller has seen its ownership of the cpu, the check sees it
too.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
| -rw-r--r-- | kernel/sched/ext/ext.c | 12 | ||||
| -rw-r--r-- | kernel/sched/ext/internal.h | 9 |
2 files changed, 20 insertions, 1 deletions
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c index 81c2d8eeae41..fd88b4d4f12a 100644 --- a/kernel/sched/ext/ext.c +++ b/kernel/sched/ext/ext.c @@ -1071,6 +1071,18 @@ void schedule_dsq_reenq(struct scx_sched *sch, struct scx_dispatch_q *dsq, if (dsq->id == SCX_DSQ_LOCAL) { rq = container_of(dsq, struct rq, scx.local_dsq); + /* + * A sub-sched lacking baseline access on the target cid has no + * business triggering IPIs. The lockless test is fine: slipping + * through right after a revoke is harmless and a wrong denial + * can't happen - if the caller has seen its ownership, so does + * this test. + */ + if (unlikely(scx_missing_caps(sch, cpu_of(rq), SCX_CAP_BASE))) { + __scx_add_event(sch, SCX_EV_SUB_REENQ_DENIED, 1); + return; + } + struct scx_sched_pcpu *sch_pcpu = per_cpu_ptr(sch->pcpu, cpu_of(rq)); struct scx_deferred_reenq_local *drl = &sch_pcpu->deferred_reenq_local; diff --git a/kernel/sched/ext/internal.h b/kernel/sched/ext/internal.h index a9a853a71061..1bdf34f3fc3c 100644 --- a/kernel/sched/ext/internal.h +++ b/kernel/sched/ext/internal.h @@ -1193,6 +1193,12 @@ struct scx_event_stats { * kick degrades to a plain reschedule. */ s64 SCX_EV_SUB_PREEMPT_DENIED; + + /* + * The number of times a local DSQ reenq was dropped because the + * sub-sched lacked baseline access on the target cid. + */ + s64 SCX_EV_SUB_REENQ_DENIED; }; #define SCX_EVENTS_LIST(SCX_EVENT) \ @@ -1212,7 +1218,8 @@ struct scx_event_stats { SCX_EVENT(SCX_EV_INSERT_NOT_OWNED); \ SCX_EVENT(SCX_EV_SUB_BYPASS_DISPATCH); \ SCX_EVENT(SCX_EV_SUB_FORCED_ADMIT); \ - SCX_EVENT(SCX_EV_SUB_PREEMPT_DENIED) + SCX_EVENT(SCX_EV_SUB_PREEMPT_DENIED); \ + SCX_EVENT(SCX_EV_SUB_REENQ_DENIED) struct scx_sched; |
