]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
sched/deadline: Initialize dl_servers after SMP
authorJuri Lelli <juri.lelli@redhat.com>
Fri, 27 Jun 2025 11:51:14 +0000 (13:51 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 14 Jul 2025 08:59:32 +0000 (10:59 +0200)
dl-servers are currently initialized too early at boot when CPUs are not
fully up (only boot CPU is). This results in miscalculation of per
runqueue DEADLINE variables like extra_bw (which needs a stable CPU
count).

Move initialization of dl-servers later on after SMP has been
initialized and CPUs are all online, so that CPU count is stable and
DEADLINE variables can be computed correctly.

Fixes: d741f297bceaf ("sched/fair: Fair server interface")
Reported-by: Marcel Ziswiler <marcel.ziswiler@codethink.co.uk>
Signed-off-by: Juri Lelli <juri.lelli@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Waiman Long <longman@redhat.com>
Tested-by: Marcel Ziswiler <marcel.ziswiler@codethink.co.uk> # nuc & rock5b
Link: https://lore.kernel.org/r/20250627115118.438797-2-juri.lelli@redhat.com
kernel/sched/core.c
kernel/sched/deadline.c
kernel/sched/sched.h

index 2f8caa9db78d58bfc86dbbe9bc021d029640bbce..89b3ed637465b1b4890069cba18b7c5036f1db11 100644 (file)
@@ -8371,6 +8371,8 @@ void __init sched_init_smp(void)
        init_sched_rt_class();
        init_sched_dl_class();
 
+       sched_init_dl_servers();
+
        sched_smp_initialized = true;
 }
 
index 23668fc60bd34bf8d0f1fedb425cbc12eab6ed63..0d25553f2c178657f34ceb407d171f97811f6da2 100644 (file)
@@ -761,6 +761,8 @@ static inline void setup_new_dl_entity(struct sched_dl_entity *dl_se)
        struct dl_rq *dl_rq = dl_rq_of_se(dl_se);
        struct rq *rq = rq_of_dl_rq(dl_rq);
 
+       update_rq_clock(rq);
+
        WARN_ON(is_dl_boosted(dl_se));
        WARN_ON(dl_time_before(rq_clock(rq), dl_se->deadline));
 
@@ -1585,23 +1587,7 @@ void dl_server_start(struct sched_dl_entity *dl_se)
 {
        struct rq *rq = dl_se->rq;
 
-       /*
-        * XXX: the apply do not work fine at the init phase for the
-        * fair server because things are not yet set. We need to improve
-        * this before getting generic.
-        */
-       if (!dl_server(dl_se)) {
-               u64 runtime =  50 * NSEC_PER_MSEC;
-               u64 period = 1000 * NSEC_PER_MSEC;
-
-               dl_server_apply_params(dl_se, runtime, period, 1);
-
-               dl_se->dl_server = 1;
-               dl_se->dl_defer = 1;
-               setup_new_dl_entity(dl_se);
-       }
-
-       if (!dl_se->dl_runtime || dl_se->dl_server_active)
+       if (!dl_server(dl_se) || dl_se->dl_server_active)
                return;
 
        dl_se->dl_server_active = 1;
@@ -1612,7 +1598,7 @@ void dl_server_start(struct sched_dl_entity *dl_se)
 
 void dl_server_stop(struct sched_dl_entity *dl_se)
 {
-       if (!dl_se->dl_runtime)
+       if (!dl_server(dl_se) || !dl_server_active(dl_se))
                return;
 
        dequeue_dl_entity(dl_se, DEQUEUE_SLEEP);
@@ -1645,6 +1631,32 @@ void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
        dl_se->server_pick_task = pick_task;
 }
 
+void sched_init_dl_servers(void)
+{
+       int cpu;
+       struct rq *rq;
+       struct sched_dl_entity *dl_se;
+
+       for_each_online_cpu(cpu) {
+               u64 runtime =  50 * NSEC_PER_MSEC;
+               u64 period = 1000 * NSEC_PER_MSEC;
+
+               rq = cpu_rq(cpu);
+
+               guard(rq_lock_irq)(rq);
+
+               dl_se = &rq->fair_server;
+
+               WARN_ON(dl_server(dl_se));
+
+               dl_server_apply_params(dl_se, runtime, period, 1);
+
+               dl_se->dl_server = 1;
+               dl_se->dl_defer = 1;
+               setup_new_dl_entity(dl_se);
+       }
+}
+
 void __dl_server_attach_root(struct sched_dl_entity *dl_se, struct rq *rq)
 {
        u64 new_bw = dl_se->dl_bw;
index 105190b18020318a3f39f6bbf8d3d5e6c968acd4..3058fb6246dab8e83cb18f508ddff8708a697800 100644 (file)
@@ -385,6 +385,7 @@ 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 sched_init_dl_servers(void);
 
 extern void dl_server_update_idle_time(struct rq *rq,
                    struct task_struct *p);