[PATCH v4 21/26] sched/deadline: Cancel the replenishment timer with the parameters
From: Mathieu Desnoyers
Date: Fri Nov 06 2026 - 20:50:37 EST
The replenishment timer of a throttled task is armed for its next
period, which can come after its 0-lag time: a task that yielded keeps
runtime, and a constrained-deadline task that overruns by little
reaches its 0-lag time within the same period. Leaving SCHED_DEADLINE,
such a task has its parameters cleared at the 0-lag time with that
timer still armed.
Back in the class before it fires, the task throttles again, and
start_dl_timer() leaves the armed timer where it is:
if (!hrtimer_is_queued(timer)) {
if (!dl_server(dl_se))
get_task_struct(dl_task_of(dl_se));
hrtimer_start(timer, act, HRTIMER_MODE_ABS_HARD);
}
so the replenishment comes at the period of the reservation the task
left: too early, which hands it runtime it has not earned, or up to a
period too late.
Commit a649f237db18 ("sched,dl: Fix sched class hopping CBS hole") left
that timer armed on purpose, as what reset a task that stayed out of
the class. The 0-lag time took that over and left the timer behind:
cancel it where the parameters go, and where switched_from_dl()
releases the bandwidth of a task that leaves asleep past its 0-lag
time, a constrained task that overran as it blocked having the timer
armed there too.
Fixes: 209a0cbda7a0 ("sched/deadline: Improve the tracking of active utilization")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@xxxxxxxxxxxx>
---
kernel/sched/deadline.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index ed951246e3d2..a0b05ff8c6da 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -607,6 +607,7 @@ static void task_non_contending(struct sched_dl_entity *dl_se, bool dl_task)
if (dl_task && READ_ONCE(p->__state) == TASK_DEAD)
sub_rq_bw(dl_se, &rq->dl);
dl_task_release_bw(p);
+ cancel_replenish_timer(dl_se);
__dl_clear_params(dl_se);
}
}
@@ -2375,6 +2376,7 @@ static enum hrtimer_restart inactive_task_timer(struct hrtimer *timer)
}
dl_task_release_bw(p);
+ cancel_replenish_timer(dl_se);
__dl_clear_params(dl_se);
goto unlock;
@@ -4009,8 +4011,10 @@ static void switched_from_dl(struct rq *rq, struct task_struct *p)
* dl_non_contending cleared under it by migrate_task_rq_dl():
* it finds !dl_task(p).
*/
- if (released)
+ if (released) {
+ cancel_replenish_timer(&p->dl);
__dl_clear_params(&p->dl);
+ }
}
/*
--
2.47.3