[PATCH 04/14] sched: Cleanup sched_delayed handling for class switches

Peter Zijlstra
2025-09-10T16:00:43Z

Use the new sched_class::switching_from() method to dequeue delayed
tasks before switching to another class.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
kernel/sched/core.c | 12 ++++++++----
kernel/sched/ext.c | 6 ------
kernel/sched/fair.c | 7 +++++++
kernel/sched/syscalls.c | 3 ---
4 files changed, 15 insertions(+), 13 deletions(-)

--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7403,9 +7403,6 @@ void rt_mutex_setprio(struct task_struct
queue_flag &= ~(DEQUEUE_SAVE | DEQUEUE_MOVE);
}

- if (prev_class != next_class && p->se.sched_delayed)
- dequeue_task(rq, p, DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK);
-
scoped_guard (sched_change, p, queue_flag) {
/*
* Boosting condition are:
@@ -10879,8 +10876,15 @@ struct sched_change_ctx *sched_change_be
if (WARN_ON_ONCE(flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)))
flags &= ~(DEQUEUE_SAVE | DEQUEUE_MOVE);

- if (p->sched_class->switching_from)
+ if (p->sched_class->switching_from) {
+ /*
+ * switching_from_fair() assumes CLASS implies NOCLOCK;
+ * fixing this assumption would mean switching_from()
+ * would need to be able to change flags.
+ */
+ WARN_ON(!(flags & DEQUEUE_NOCLOCK));
p->sched_class->switching_from(rq, p);
+ }
}

*ctx = (struct sched_change_ctx){
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -5011,9 +5011,6 @@ static void scx_disable_workfn(struct kt
queue_flags &= ~(DEQUEUE_SAVE | DEQUEUE_MOVE);
}

- if (old_class != new_class && p->se.sched_delayed)
- dequeue_task(task_rq(p), p, DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK);
-
scoped_guard (sched_change, p, queue_flags) {
p->sched_class = new_class;
}
@@ -5764,9 +5761,6 @@ static int scx_enable(struct sched_ext_o
queue_flags &= ~(DEQUEUE_SAVE | DEQUEUE_MOVE);
}

- if (old_class != new_class && p->se.sched_delayed)
- dequeue_task(task_rq(p), p, DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK);
-
scoped_guard (sched_change, p, queue_flags) {
p->scx.slice = SCX_SLICE_DFL;
p->sched_class = new_class;
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -13221,6 +13221,12 @@ static void attach_task_cfs_rq(struct ta
attach_entity_cfs_rq(se);
}

+static void switching_from_fair(struct rq *rq, struct task_struct *p)
+{
+ if (p->se.sched_delayed)
+ dequeue_task(rq, p, DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK);
+}
+
static void switched_from_fair(struct rq *rq, struct task_struct *p)
{
detach_task_cfs_rq(p);
@@ -13622,6 +13628,7 @@ DEFINE_SCHED_CLASS(fair) = {

.reweight_task = reweight_task_fair,
.prio_changed = prio_changed_fair,
+ .switching_from = switching_from_fair,
.switched_from = switched_from_fair,
.switched_to = switched_to_fair,

--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -689,9 +689,6 @@ int __sched_setscheduler(struct task_str
queue_flags &= ~(DEQUEUE_SAVE | DEQUEUE_MOVE);
}

- if (prev_class != next_class && p->se.sched_delayed)
- dequeue_task(rq, p, DEQUEUE_SLEEP | DEQUEUE_DELAYED | DEQUEUE_NOCLOCK);
-
scoped_guard (sched_change, p, queue_flags) {

if (!(attr->sched_flags & SCHED_FLAG_KEEP_PARAMS)) {