* [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f
[not found] <https://lore.kernel.org/stable/20260522213120.1205100-1-lbckmnn@mailbox.org/>
@ 2026-05-25 21:11 ` Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 1/5] sched/deadline: Less agressive dl_server handling Lukas Beckmann
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Lukas Beckmann @ 2026-05-25 21:11 UTC (permalink / raw)
To: Sasha Levin
Cc: stable, regressions, Mike Galbraith, Peter Zijlstra, Juri Lelli
Commit d66792919d4f ("sched/deadline: Use revised wakeup rule for
dl_server") in the 6.12.y stable tree (upstream commit 14a857056466)
depends on five upstream commits that were not backported:
commit cccb45d7c429 ("sched/deadline: Less agressive dl_server handling")
commit 4717432dfd99 ("sched/deadline: Fix dl_server_stopped()")
commit bb4700adc3ab ("sched/deadline: Always stop dl-server before changing parameters")
commit 4ae8d9aa9f9d ("sched/deadline: Fix dl_server getting stuck")
commit a3a70caf7906 ("sched/deadline: Fix dl_server behaviour")
Without these, cyclictest under load reports latencies up to ~50ms on
PREEMPT_RT.
For context, see the regression report:
https://lore.kernel.org/regressions/04657838-46d1-432d-95e1-eb73b930b032@mailbox.org
Testing:
Tested on two different machines with Debian's PREEMPT_RT config for about
10 hours.
Without these patches cyclictest under load spikes to ~50ms in less than
30 minutes, with the series applied the latency spikes are gone.
Thanks,
Lukas
v1: https://lore.kernel.org/stable/20260522213120.1205100-1-lbckmnn@mailbox.org/
v1 -> v2:
- Also pick up
4717432dfd99 ("sched/deadline: Fix dl_server_stopped()") and
bb4700adc3ab ("sched/deadline: Always stop dl-server before changing parameters")
- drop the conflict resolution from a3a70caf7906 as it applies cleanly now
Huacai Chen (1):
sched/deadline: Fix dl_server_stopped()
Juri Lelli (1):
sched/deadline: Always stop dl-server before changing parameters
Peter Zijlstra (3):
sched/deadline: Less agressive dl_server handling
sched/deadline: Fix dl_server getting stuck
sched/deadline: Fix dl_server behaviour
include/linux/sched.h | 1 -
kernel/sched/deadline.c | 16 +++-------------
kernel/sched/debug.c | 6 ++----
kernel/sched/fair.c | 16 +---------------
kernel/sched/sched.h | 37 +++++++++++++++++++++++++++++++------
5 files changed, 37 insertions(+), 39 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 6.12.y v2 1/5] sched/deadline: Less agressive dl_server handling
2026-05-25 21:11 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Lukas Beckmann
@ 2026-05-25 21:11 ` Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 2/5] sched/deadline: Fix dl_server_stopped() Lukas Beckmann
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Lukas Beckmann @ 2026-05-25 21:11 UTC (permalink / raw)
To: Sasha Levin
Cc: stable, regressions, Mike Galbraith, Peter Zijlstra, Juri Lelli
From: Peter Zijlstra <peterz@infradead.org>
commit cccb45d7c4295bbfeba616582d0249f2d21e6df5 upstream.
Chris reported that commit 5f6bd380c7bd ("sched/rt: Remove default
bandwidth control") caused a significant dip in his favourite
benchmark of the day. Simply disabling dl_server cured things.
His workload hammers the 0->1, 1->0 transitions, and the
dl_server_{start,stop}() overhead kills it -- fairly obviously a bad
idea in hind sight and all that.
Change things around to only disable the dl_server when there has not
been a fair task around for a whole period. Since the default period
is 1 second, this ensures the benchmark never trips this, overhead
gone.
Fixes: 557a6bfc662c ("sched/fair: Add trivial fair server")
Reported-by: Chris Mason <clm@meta.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Juri Lelli <juri.lelli@redhat.com>
Acked-by: Juri Lelli <juri.lelli@redhat.com>
Link: https://lkml.kernel.org/r/20250702121158.465086194@infradead.org
[ adjust context for renamed/removed variable names ]
Signed-off-by: Lukas Beckmann <lbckmnn@mailbox.org>
---
include/linux/sched.h | 1 +
kernel/sched/deadline.c | 25 ++++++++++++++++++++++---
kernel/sched/fair.c | 9 ---------
3 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2e4c437c7c90..299a65a92d2e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -674,6 +674,7 @@ struct sched_dl_entity {
unsigned int dl_defer : 1;
unsigned int dl_defer_armed : 1;
unsigned int dl_defer_running : 1;
+ unsigned int dl_server_idle : 1;
/*
* Bandwidth enforcement timer. Each -deadline task has its
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 1ef891f8e3f2..9c5fa95b345a 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1201,6 +1201,8 @@ static void __push_dl_task(struct rq *rq, struct rq_flags *rf)
/* a defer timer will not be reset if the runtime consumed was < dl_server_min_res */
static const u64 dl_server_min_res = 1 * NSEC_PER_MSEC;
+static bool dl_server_stopped(struct sched_dl_entity *dl_se);
+
static enum hrtimer_restart dl_server_timer(struct hrtimer *timer, struct sched_dl_entity *dl_se)
{
struct rq *rq = rq_of_dl_se(dl_se);
@@ -1220,6 +1222,7 @@ static enum hrtimer_restart dl_server_timer(struct hrtimer *timer, struct sched_
if (!dl_se->server_has_tasks(dl_se)) {
replenish_dl_entity(dl_se);
+ dl_server_stopped(dl_se);
return HRTIMER_NORESTART;
}
@@ -1626,8 +1629,10 @@ void dl_server_update_idle_time(struct rq *rq, struct task_struct *p)
void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)
{
/* 0 runtime = fair server disabled */
- if (dl_se->dl_runtime)
+ if (dl_se->dl_runtime) {
+ dl_se->dl_server_idle = 0;
update_curr_dl_se(dl_se->rq, dl_se, delta_exec);
+ }
}
/*
@@ -1850,7 +1855,7 @@ void dl_server_start(struct sched_dl_entity *dl_se)
setup_new_dl_entity(dl_se);
}
- if (!dl_se->dl_runtime)
+ if (!dl_se->dl_runtime || dl_se->dl_server_active)
return;
dl_se->dl_server_active = 1;
@@ -1871,6 +1876,20 @@ void dl_server_stop(struct sched_dl_entity *dl_se)
dl_se->dl_server_active = 0;
}
+static bool dl_server_stopped(struct sched_dl_entity *dl_se)
+{
+ if (!dl_se->dl_server_active)
+ return false;
+
+ if (dl_se->dl_server_idle) {
+ dl_server_stop(dl_se);
+ return true;
+ }
+
+ dl_se->dl_server_idle = 1;
+ return false;
+}
+
void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
dl_server_has_tasks_f has_tasks,
dl_server_pick_f pick_task)
@@ -2628,7 +2647,7 @@ static struct task_struct *__pick_task_dl(struct rq *rq)
if (dl_server(dl_se)) {
p = dl_se->server_pick_task(dl_se);
if (!p) {
- if (dl_server_active(dl_se)) {
+ if (!dl_server_stopped(dl_se)) {
dl_se->dl_yielded = 1;
update_curr_dl_se(rq, dl_se, 0);
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index a0a47e50b71c..d26e078d0623 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5972,7 +5972,6 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)
struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg);
struct sched_entity *se;
long queued_delta, runnable_delta, idle_task_delta, delayed_delta, dequeue = 1;
- long rq_h_nr_queued = rq->cfs.h_nr_queued;
raw_spin_lock(&cfs_b->lock);
/* This will start the period timer if necessary */
@@ -6059,10 +6058,6 @@ static bool throttle_cfs_rq(struct cfs_rq *cfs_rq)
/* At this point se is NULL and we are at root level*/
sub_nr_running(rq, queued_delta);
-
- /* Stop the fair server if throttling resulted in no runnable tasks */
- if (rq_h_nr_queued && !rq->cfs.h_nr_queued)
- dl_server_stop(&rq->fair_server);
done:
/*
* Note: distribution will already see us throttled via the
@@ -7162,7 +7157,6 @@ static void set_next_buddy(struct sched_entity *se);
static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags)
{
bool was_sched_idle = sched_idle_rq(rq);
- int rq_h_nr_queued = rq->cfs.h_nr_queued;
bool task_sleep = flags & DEQUEUE_SLEEP;
bool task_delayed = flags & DEQUEUE_DELAYED;
struct task_struct *p = NULL;
@@ -7251,9 +7245,6 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags)
sub_nr_running(rq, h_nr_queued);
- if (rq_h_nr_queued && !rq->cfs.h_nr_queued)
- dl_server_stop(&rq->fair_server);
-
/* balance early to pull high priority tasks */
if (unlikely(!was_sched_idle && sched_idle_rq(rq)))
rq->next_balance = jiffies;
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6.12.y v2 2/5] sched/deadline: Fix dl_server_stopped()
2026-05-25 21:11 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 1/5] sched/deadline: Less agressive dl_server handling Lukas Beckmann
@ 2026-05-25 21:11 ` Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 3/5] sched/deadline: Always stop dl-server before changing parameters Lukas Beckmann
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Lukas Beckmann @ 2026-05-25 21:11 UTC (permalink / raw)
To: Sasha Levin
Cc: stable, regressions, Mike Galbraith, Peter Zijlstra, Juri Lelli
From: Huacai Chen <chenhuacai@loongson.cn>
commit 4717432dfd99bbd015b6782adca216c6f9340038 upstream.
Commit cccb45d7c429 ("sched/deadline: Less agressive dl_server handling")
introduces dl_server_stopped(). But it is obvious that dl_server_stopped()
should return true if dl_se->dl_server_active is 0.
Fixes: cccb45d7c429 ("sched/deadline: Less agressive dl_server handling")
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20250809130419.1980742-1-chenhuacai@loongson.cn
Signed-off-by: Lukas Beckmann <lbckmnn@mailbox.org>
---
kernel/sched/deadline.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 9c5fa95b345a..6ff9055a6981 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1879,7 +1879,7 @@ void dl_server_stop(struct sched_dl_entity *dl_se)
static bool dl_server_stopped(struct sched_dl_entity *dl_se)
{
if (!dl_se->dl_server_active)
- return false;
+ return true;
if (dl_se->dl_server_idle) {
dl_server_stop(dl_se);
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6.12.y v2 3/5] sched/deadline: Always stop dl-server before changing parameters
2026-05-25 21:11 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 1/5] sched/deadline: Less agressive dl_server handling Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 2/5] sched/deadline: Fix dl_server_stopped() Lukas Beckmann
@ 2026-05-25 21:11 ` Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 4/5] sched/deadline: Fix dl_server getting stuck Lukas Beckmann
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Lukas Beckmann @ 2026-05-25 21:11 UTC (permalink / raw)
To: Sasha Levin
Cc: stable, regressions, Mike Galbraith, Peter Zijlstra, Juri Lelli
From: Juri Lelli <juri.lelli@redhat.com>
commit bb4700adc3abec34c0a38b64f66258e4e233fc16 upstream.
Commit cccb45d7c4295 ("sched/deadline: Less agressive dl_server
handling") reduced dl-server overhead by delaying disabling servers only
after there are no fair task around for a whole period, which means that
deadline entities are not dequeued right away on a server stop event.
However, the delay opens up a window in which a request for changing
server parameters can break per-runqueue running_bw tracking, as
reported by Yuri.
Close the problematic window by unconditionally calling dl_server_stop()
before applying the new parameters (ensuring deadline entities go
through an actual dequeue).
Fixes: cccb45d7c4295 ("sched/deadline: Less agressive dl_server handling")
Reported-by: Yuri Andriaccio <yurand2000@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Valentin Schneider <vschneid@redhat.com>
Link: https://lore.kernel.org/r/20250721-upstream-fix-dlserver-lessaggressive-b4-v1-1-4ebc10c87e40@redhat.com
Signed-off-by: Lukas Beckmann <lbckmnn@mailbox.org>
---
kernel/sched/debug.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 7d14e9fa53ac..564ea17ae405 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -378,10 +378,8 @@ static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubu
return -EINVAL;
}
- if (rq->cfs.h_nr_queued) {
- update_rq_clock(rq);
- dl_server_stop(&rq->fair_server);
- }
+ update_rq_clock(rq);
+ dl_server_stop(&rq->fair_server);
retval = dl_server_apply_params(&rq->fair_server, runtime, period, 0);
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6.12.y v2 4/5] sched/deadline: Fix dl_server getting stuck
2026-05-25 21:11 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Lukas Beckmann
` (2 preceding siblings ...)
2026-05-25 21:11 ` [PATCH 6.12.y v2 3/5] sched/deadline: Always stop dl-server before changing parameters Lukas Beckmann
@ 2026-05-25 21:11 ` Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 5/5] sched/deadline: Fix dl_server behaviour Lukas Beckmann
2026-05-26 11:35 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Sasha Levin
5 siblings, 0 replies; 7+ messages in thread
From: Lukas Beckmann @ 2026-05-25 21:11 UTC (permalink / raw)
To: Sasha Levin
Cc: stable, regressions, Mike Galbraith, Peter Zijlstra, Juri Lelli
From: Peter Zijlstra <peterz@infradead.org>
commit 4ae8d9aa9f9dc7137ea5e564d79c5aa5af1bc45c upstream.
John found it was easy to hit lockup warnings when running locktorture
on a 2 CPU VM, which he bisected down to: commit cccb45d7c429
("sched/deadline: Less agressive dl_server handling").
While debugging it seems there is a chance where we end up with the
dl_server dequeued, with dl_se->dl_server_active. This causes
dl_server_start() to return without enqueueing the dl_server, thus it
fails to run when RT tasks starve the cpu.
When this happens, dl_server_timer() catches the
'!dl_se->server_has_tasks(dl_se)' case, which then calls
replenish_dl_entity() and dl_server_stopped() and finally return
HRTIMER_NO_RESTART.
This ends in no new timer and also no enqueue, leaving the dl_server
'dead', allowing starvation.
What should have happened is for the bandwidth timer to start the
zero-laxity timer, which in turn would enqueue the dl_server and cause
dl_se->server_pick_task() to be called -- which will stop the
dl_server if no fair tasks are observed for a whole period.
IOW, it is totally irrelevant if there are fair tasks at the moment of
bandwidth refresh.
This removes all dl_se->server_has_tasks() users, so remove the whole
thing.
Fixes: cccb45d7c4295 ("sched/deadline: Less agressive dl_server handling")
Reported-by: John Stultz <jstultz@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: John Stultz <jstultz@google.com>
[ adjust renamed variable in fair_server_has_tasks (which this patch
removes) ]
Signed-off-by: Lukas Beckmann <lbckmnn@mailbox.org>
---
include/linux/sched.h | 1 -
kernel/sched/deadline.c | 12 +-----------
kernel/sched/fair.c | 7 +------
kernel/sched/sched.h | 4 ----
4 files changed, 2 insertions(+), 22 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 299a65a92d2e..464d281aa2e4 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -701,7 +701,6 @@ struct sched_dl_entity {
* runnable task.
*/
struct rq *rq;
- dl_server_has_tasks_f server_has_tasks;
dl_server_pick_f server_pick_task;
#ifdef CONFIG_RT_MUTEXES
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 6ff9055a6981..609783d7de29 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -916,7 +916,7 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se)
*/
if (dl_se->dl_defer && !dl_se->dl_defer_running &&
dl_time_before(rq_clock(dl_se->rq), dl_se->deadline - dl_se->runtime)) {
- if (!is_dl_boosted(dl_se) && dl_se->server_has_tasks(dl_se)) {
+ if (!is_dl_boosted(dl_se)) {
/*
* Set dl_se->dl_defer_armed and dl_throttled variables to
@@ -1201,8 +1201,6 @@ static void __push_dl_task(struct rq *rq, struct rq_flags *rf)
/* a defer timer will not be reset if the runtime consumed was < dl_server_min_res */
static const u64 dl_server_min_res = 1 * NSEC_PER_MSEC;
-static bool dl_server_stopped(struct sched_dl_entity *dl_se);
-
static enum hrtimer_restart dl_server_timer(struct hrtimer *timer, struct sched_dl_entity *dl_se)
{
struct rq *rq = rq_of_dl_se(dl_se);
@@ -1220,12 +1218,6 @@ static enum hrtimer_restart dl_server_timer(struct hrtimer *timer, struct sched_
if (!dl_se->dl_runtime)
return HRTIMER_NORESTART;
- if (!dl_se->server_has_tasks(dl_se)) {
- replenish_dl_entity(dl_se);
- dl_server_stopped(dl_se);
- return HRTIMER_NORESTART;
- }
-
if (dl_se->dl_defer_armed) {
/*
* First check if the server could consume runtime in background.
@@ -1891,11 +1883,9 @@ static bool dl_server_stopped(struct sched_dl_entity *dl_se)
}
void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
- dl_server_has_tasks_f has_tasks,
dl_server_pick_f pick_task)
{
dl_se->rq = rq;
- dl_se->server_has_tasks = has_tasks;
dl_se->server_pick_task = pick_task;
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d26e078d0623..f36512892adf 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -9058,11 +9058,6 @@ static struct task_struct *__pick_next_task_fair(struct rq *rq, struct task_stru
return pick_next_task_fair(rq, prev, NULL);
}
-static bool fair_server_has_tasks(struct sched_dl_entity *dl_se)
-{
- return !!dl_se->rq->cfs.nr_running;
-}
-
static struct task_struct *fair_server_pick_task(struct sched_dl_entity *dl_se)
{
return pick_task_fair(dl_se->rq);
@@ -9074,7 +9069,7 @@ void fair_server_init(struct rq *rq)
init_dl_entity(dl_se);
- dl_server_init(dl_se, rq, fair_server_has_tasks, fair_server_pick_task);
+ dl_server_init(dl_se, rq, fair_server_pick_task);
}
/*
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index a09e2d25edd5..9391ff62cdaa 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -371,9 +371,6 @@ extern s64 dl_scaled_delta_exec(struct rq *rq, struct sched_dl_entity *dl_se, s6
*
* dl_se::rq -- runqueue we belong to.
*
- * dl_se::server_has_tasks() -- used on bandwidth enforcement; we 'stop' the
- * server when it runs out of tasks to run.
- *
* dl_se::server_pick() -- nested pick_next_task(); we yield the period if this
* returns NULL.
*
@@ -389,7 +386,6 @@ extern void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec);
extern void dl_server_start(struct sched_dl_entity *dl_se);
extern void dl_server_stop(struct sched_dl_entity *dl_se);
extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
- dl_server_has_tasks_f has_tasks,
dl_server_pick_f pick_task);
extern void dl_server_update_idle_time(struct rq *rq,
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 6.12.y v2 5/5] sched/deadline: Fix dl_server behaviour
2026-05-25 21:11 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Lukas Beckmann
` (3 preceding siblings ...)
2026-05-25 21:11 ` [PATCH 6.12.y v2 4/5] sched/deadline: Fix dl_server getting stuck Lukas Beckmann
@ 2026-05-25 21:11 ` Lukas Beckmann
2026-05-26 11:35 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Sasha Levin
5 siblings, 0 replies; 7+ messages in thread
From: Lukas Beckmann @ 2026-05-25 21:11 UTC (permalink / raw)
To: Sasha Levin
Cc: stable, regressions, Mike Galbraith, Peter Zijlstra, Juri Lelli
From: Peter Zijlstra <peterz@infradead.org>
commit a3a70caf7906708bf9bbc80018752a6b36543808 upstream.
John reported undesirable behaviour with the dl_server since commit:
cccb45d7c4295 ("sched/deadline: Less agressive dl_server handling").
When starving fair tasks on purpose (starting spinning FIFO tasks),
his fair workload, which often goes (briefly) idle, would delay fair
invocations for a second, running one invocation per second was both
unexpected and terribly slow.
The reason this happens is that when dl_se->server_pick_task() returns
NULL, indicating no runnable tasks, it would yield, pushing any later
jobs out a whole period (1 second).
Instead simply stop the server. This should restore behaviour in that
a later wakeup (which restarts the server) will be able to continue
running (subject to the CBS wakeup rules).
Notably, this does not re-introduce the behaviour cccb45d7c4295 set
out to solve, any start/stop cycle is naturally throttled by the timer
period (no active cancel).
Fixes: cccb45d7c4295 ("sched/deadline: Less agressive dl_server handling")
Reported-by: John Stultz <jstultz@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: John Stultz <jstultz@google.com>
Closes: https://lore.kernel.org/regressions/04657838-46d1-432d-95e1-eb73b930b032@mailbox.org
Signed-off-by: Lukas Beckmann <lbckmnn@mailbox.org>
---
include/linux/sched.h | 1 -
kernel/sched/deadline.c | 23 ++---------------------
kernel/sched/sched.h | 33 +++++++++++++++++++++++++++++++--
3 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 464d281aa2e4..f9ffe42cae17 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -674,7 +674,6 @@ struct sched_dl_entity {
unsigned int dl_defer : 1;
unsigned int dl_defer_armed : 1;
unsigned int dl_defer_running : 1;
- unsigned int dl_server_idle : 1;
/*
* Bandwidth enforcement timer. Each -deadline task has its
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 609783d7de29..a6c699e43111 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1621,10 +1621,8 @@ void dl_server_update_idle_time(struct rq *rq, struct task_struct *p)
void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)
{
/* 0 runtime = fair server disabled */
- if (dl_se->dl_runtime) {
- dl_se->dl_server_idle = 0;
+ if (dl_se->dl_runtime)
update_curr_dl_se(dl_se->rq, dl_se, delta_exec);
- }
}
/*
@@ -1868,20 +1866,6 @@ void dl_server_stop(struct sched_dl_entity *dl_se)
dl_se->dl_server_active = 0;
}
-static bool dl_server_stopped(struct sched_dl_entity *dl_se)
-{
- if (!dl_se->dl_server_active)
- return true;
-
- if (dl_se->dl_server_idle) {
- dl_server_stop(dl_se);
- return true;
- }
-
- dl_se->dl_server_idle = 1;
- return false;
-}
-
void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
dl_server_pick_f pick_task)
{
@@ -2637,10 +2621,7 @@ static struct task_struct *__pick_task_dl(struct rq *rq)
if (dl_server(dl_se)) {
p = dl_se->server_pick_task(dl_se);
if (!p) {
- if (!dl_server_stopped(dl_se)) {
- dl_se->dl_yielded = 1;
- update_curr_dl_se(rq, dl_se, 0);
- }
+ dl_server_stop(dl_se);
goto again;
}
rq->dl_server = dl_se;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 9391ff62cdaa..7956abeb9154 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -377,10 +377,39 @@ extern s64 dl_scaled_delta_exec(struct rq *rq, struct sched_dl_entity *dl_se, s6
* dl_server_update() -- called from update_curr_common(), propagates runtime
* to the server.
*
- * dl_server_start()
- * dl_server_stop() -- start/stop the server when it has (no) tasks.
+ * dl_server_start() -- start the server when it has tasks; it will stop
+ * automatically when there are no more tasks, per
+ * dl_se::server_pick() returning NULL.
+ *
+ * dl_server_stop() -- (force) stop the server; use when updating
+ * parameters.
*
* dl_server_init() -- initializes the server.
+ *
+ * When started the dl_server will (per dl_defer) schedule a timer for its
+ * zero-laxity point -- that is, unlike regular EDF tasks which run ASAP, a
+ * server will run at the very end of its period.
+ *
+ * This is done such that any runtime from the target class can be accounted
+ * against the server -- through dl_server_update() above -- such that when it
+ * becomes time to run, it might already be out of runtime and get deferred
+ * until the next period. In this case dl_server_timer() will alternate
+ * between defer and replenish but never actually enqueue the server.
+ *
+ * Only when the target class does not manage to exhaust the server's runtime
+ * (there's actualy starvation in the given period), will the dl_server get on
+ * the runqueue. Once queued it will pick tasks from the target class and run
+ * them until either its runtime is exhaused, at which point its back to
+ * dl_server_timer, or until there are no more tasks to run, at which point
+ * the dl_server stops itself.
+ *
+ * By stopping at this point the dl_server retains bandwidth, which, if a new
+ * task wakes up imminently (starting the server again), can be used --
+ * subject to CBS wakeup rules -- without having to wait for the next period.
+ *
+ * Additionally, because of the dl_defer behaviour the start/stop behaviour is
+ * naturally thottled to once per period, avoiding high context switch
+ * workloads from spamming the hrtimer program/cancel paths.
*/
extern void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec);
extern void dl_server_start(struct sched_dl_entity *dl_se);
--
2.54.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f
2026-05-25 21:11 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Lukas Beckmann
` (4 preceding siblings ...)
2026-05-25 21:11 ` [PATCH 6.12.y v2 5/5] sched/deadline: Fix dl_server behaviour Lukas Beckmann
@ 2026-05-26 11:35 ` Sasha Levin
5 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-05-26 11:35 UTC (permalink / raw)
To: Lukas Beckmann
Cc: Sasha Levin, stable, regressions, Mike Galbraith, Peter Zijlstra,
Juri Lelli
> v2 backports the missing dependency chain for d66792919d4f
> ("sched/deadline: Use revised wakeup rule for dl_server") in 6.12.y:
>
> 1/5 cccb45d7c429 sched/deadline: Less agressive dl_server handling
> 2/5 4717432dfd99 sched/deadline: Fix dl_server_stopped()
> 3/5 bb4700adc3ab sched/deadline: Always stop dl-server before changing parameters
> 4/5 4ae8d9aa9f9d sched/deadline: Fix dl_server getting stuck
> 5/5 a3a70caf7906 sched/deadline: Fix dl_server behaviour
Queued all 5 for 6.12.y, thanks for the quick respin.
I also pulled ee6e44dfe6e5 ("sched/deadline: Stop dl_server before
CPU goes offline") on top, since it's a Fixes: of 4ae8d9aa9f9d and
6.17.y already took it. Without it 4/5 leaves a dangling dl_server
on CPU hotunplug.
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-26 11:35 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <https://lore.kernel.org/stable/20260522213120.1205100-1-lbckmnn@mailbox.org/>
2026-05-25 21:11 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 1/5] sched/deadline: Less agressive dl_server handling Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 2/5] sched/deadline: Fix dl_server_stopped() Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 3/5] sched/deadline: Always stop dl-server before changing parameters Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 4/5] sched/deadline: Fix dl_server getting stuck Lukas Beckmann
2026-05-25 21:11 ` [PATCH 6.12.y v2 5/5] sched/deadline: Fix dl_server behaviour Lukas Beckmann
2026-05-26 11:35 ` [PATCH 6.12.y v2 0/5] backport missing dependencies of d66792919d4f Sasha Levin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.