sched/core: Fix inter-class wakeup_preempt()

The way wakeup_preempt() works since commit 704069649b ("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: 704069649b ("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
This commit is contained in:
Peter Zijlstra
2026-06-30 10:56:51 +02:00
parent dc59e4fea9
commit fa02b28684
3 changed files with 8 additions and 4 deletions
+4 -2
View File
@@ -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;
}
+2 -1
View File
@@ -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))
+2 -1
View File
@@ -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) {