diff options
| author | Peter Zijlstra <peterz@infradead.org> | 2026-06-26 09:36:52 +0200 |
|---|---|---|
| committer | Peter Zijlstra <peterz@infradead.org> | 2026-06-30 10:56:51 +0200 |
| commit | fa02b2868420d9f33d64ddcb15ef0f96880b2a6d (patch) | |
| tree | 4019d2e6adae97444ef7af81c248ca9344f0bfee | |
| parent | dc59e4fea9d83f03bad6bddf3fa2e52491777482 (diff) | |
sched/core: Fix inter-class wakeup_preempt()
The way wakeup_preempt() works since commit 704069649b5b ("sched/core: Rework
sched_class::wakeup_preempt() and rq_modified_*()") is that it will call
rq->next_class->wakeup_preempt(rq, p) when p is of an equal or higher class,
and raise ->next_class when higher.
This means that:
running idle task
wakeup fair-A
(next_class == idle)
if (sched_class_above(fair, idle)) {
wakeup_preempt_idle(fair-A);
resched_curr(rq);
next_class = fair;
}
wakeup fair-B
(next_class == fair)
if (fair == fair)
wakeup_preempt_fair(fair-B);
(but current is idle)
All wakeup_preempt_$class() methods, except for wakeup_preempt_scx() (for whoem
this was build) ignore cross-class wakeups by testing if @p is of the right
class, but per the above case, it also should check current.
This is mostly harmless in the current form, but will lead to trouble with
later patches.
Fixes: 704069649b5b ("sched/core: Rework sched_class::wakeup_preempt() and rq_modified_*()")
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260626074605.GB2568396%40noisy.programming.kicks-ass.net
| -rw-r--r-- | kernel/sched/deadline.c | 6 | ||||
| -rw-r--r-- | kernel/sched/fair.c | 3 | ||||
| -rw-r--r-- | kernel/sched/rt.c | 3 |
3 files changed, 8 insertions, 4 deletions
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 0f858b98c9aa..a3003b0f4522 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -2733,15 +2733,17 @@ static int balance_dl(struct rq *rq, struct rq_flags *rf) */ static void wakeup_preempt_dl(struct rq *rq, struct task_struct *p, int flags) { + struct task_struct *donor = rq->donor; /* * Can only get preempted by stop-class, and those should be * few and short lived, doesn't really make sense to push * anything away for that. */ - if (p->sched_class != &dl_sched_class) + if (p->sched_class != &dl_sched_class || + donor->sched_class != &dl_sched_class) return; - if (dl_entity_preempt(&p->dl, &rq->donor->dl)) { + if (dl_entity_preempt(&p->dl, &donor->dl)) { resched_curr(rq); return; } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index d78467ec6ee1..a384f169aa00 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9778,7 +9778,8 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f /* * XXX Getting preempted by higher class, try and find idle CPU? */ - if (p->sched_class != &fair_sched_class) + if (p->sched_class != &fair_sched_class || + donor->sched_class != &fair_sched_class) return; if (unlikely(se == pse)) diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index e474c31d8fe6..e6e5f8a2caaf 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1629,7 +1629,8 @@ static void wakeup_preempt_rt(struct rq *rq, struct task_struct *p, int flags) /* * XXX If we're preempted by DL, queue a push? */ - if (p->sched_class != &rt_sched_class) + if (p->sched_class != &rt_sched_class || + donor->sched_class != &rt_sched_class) return; if (p->prio < donor->prio) { |
