Skip to content

Commit 352b8a7

Browse files
Doug Bergeropsiff
authored andcommitted
sched/deadline: only set free_cpus for online runqueues
[ Upstream commit 382748c ] Commit 16b2694 ("sched/deadline: Modify cpudl::free_cpus to reflect rd->online") introduced the cpudl_set/clear_freecpu functions to allow the cpu_dl::free_cpus mask to be manipulated by the deadline scheduler class rq_on/offline callbacks so the mask would also reflect this state. Commit 9659e1e ("sched/deadline: Remove cpu_active_mask from cpudl_find()") removed the check of the cpu_active_mask to save some processing on the premise that the cpudl::free_cpus mask already reflected the runqueue online state. Unfortunately, there are cases where it is possible for the cpudl_clear function to set the free_cpus bit for a CPU when the deadline runqueue is offline. When this occurs while a CPU is connected to the default root domain the flag may retain the bad state after the CPU has been unplugged. Later, a different CPU that is transitioning through the default root domain may push a deadline task to the powered down CPU when cpudl_find sees its free_cpus bit is set. If this happens the task will not have the opportunity to run. One example is outlined here: https://lore.kernel.org/lkml/20250110233010.2339521-1-opendmb@gmail.com Another occurs when the last deadline task is migrated from a CPU that has an offlined runqueue. The dequeue_task member of the deadline scheduler class will eventually call cpudl_clear and set the free_cpus bit for the CPU. This commit modifies the cpudl_clear function to be aware of the online state of the deadline runqueue so that the free_cpus mask can be updated appropriately. It is no longer necessary to manage the mask outside of the cpudl_set/clear functions so the cpudl_set/clear_freecpu functions are removed. In addition, since the free_cpus mask is now only updated under the cpudl lock the code was changed to use the non-atomic __cpumask functions. Signed-off-by: Doug Berger <opendmb@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Sasha Levin <sashal@kernel.org> (cherry picked from commit 3ed049fbfb4d75b4e0b8ab54c934f485129d5dc8) Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
1 parent 6e37b1b commit 352b8a7

3 files changed

Lines changed: 14 additions & 32 deletions

File tree

kernel/sched/cpudeadline.c

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,13 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p,
166166
* cpudl_clear - remove a CPU from the cpudl max-heap
167167
* @cp: the cpudl max-heap context
168168
* @cpu: the target CPU
169+
* @online: the online state of the deadline runqueue
169170
*
170171
* Notes: assumes cpu_rq(cpu)->lock is locked
171172
*
172173
* Returns: (void)
173174
*/
174-
void cpudl_clear(struct cpudl *cp, int cpu)
175+
void cpudl_clear(struct cpudl *cp, int cpu, bool online)
175176
{
176177
int old_idx, new_cpu;
177178
unsigned long flags;
@@ -184,7 +185,7 @@ void cpudl_clear(struct cpudl *cp, int cpu)
184185
if (old_idx == IDX_INVALID) {
185186
/*
186187
* Nothing to remove if old_idx was invalid.
187-
* This could happen if a rq_offline_dl is
188+
* This could happen if rq_online_dl or rq_offline_dl is
188189
* called for a CPU without -dl tasks running.
189190
*/
190191
} else {
@@ -195,9 +196,12 @@ void cpudl_clear(struct cpudl *cp, int cpu)
195196
cp->elements[new_cpu].idx = old_idx;
196197
cp->elements[cpu].idx = IDX_INVALID;
197198
cpudl_heapify(cp, old_idx);
198-
199-
cpumask_set_cpu(cpu, cp->free_cpus);
200199
}
200+
if (likely(online))
201+
__cpumask_set_cpu(cpu, cp->free_cpus);
202+
else
203+
__cpumask_clear_cpu(cpu, cp->free_cpus);
204+
201205
raw_spin_unlock_irqrestore(&cp->lock, flags);
202206
}
203207

@@ -228,7 +232,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl)
228232
cp->elements[new_idx].cpu = cpu;
229233
cp->elements[cpu].idx = new_idx;
230234
cpudl_heapify_up(cp, new_idx);
231-
cpumask_clear_cpu(cpu, cp->free_cpus);
235+
__cpumask_clear_cpu(cpu, cp->free_cpus);
232236
} else {
233237
cp->elements[old_idx].dl = dl;
234238
cpudl_heapify(cp, old_idx);
@@ -237,26 +241,6 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl)
237241
raw_spin_unlock_irqrestore(&cp->lock, flags);
238242
}
239243

240-
/*
241-
* cpudl_set_freecpu - Set the cpudl.free_cpus
242-
* @cp: the cpudl max-heap context
243-
* @cpu: rd attached CPU
244-
*/
245-
void cpudl_set_freecpu(struct cpudl *cp, int cpu)
246-
{
247-
cpumask_set_cpu(cpu, cp->free_cpus);
248-
}
249-
250-
/*
251-
* cpudl_clear_freecpu - Clear the cpudl.free_cpus
252-
* @cp: the cpudl max-heap context
253-
* @cpu: rd attached CPU
254-
*/
255-
void cpudl_clear_freecpu(struct cpudl *cp, int cpu)
256-
{
257-
cpumask_clear_cpu(cpu, cp->free_cpus);
258-
}
259-
260244
/*
261245
* cpudl_init - initialize the cpudl structure
262246
* @cp: the cpudl max-heap context

kernel/sched/cpudeadline.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ struct cpudl {
1919

2020
int cpudl_find(struct cpudl *cp, struct task_struct *p, struct cpumask *later_mask);
2121
void cpudl_set(struct cpudl *cp, int cpu, u64 dl);
22-
void cpudl_clear(struct cpudl *cp, int cpu);
22+
void cpudl_clear(struct cpudl *cp, int cpu, bool online);
2323
int cpudl_init(struct cpudl *cp);
24-
void cpudl_set_freecpu(struct cpudl *cp, int cpu);
25-
void cpudl_clear_freecpu(struct cpudl *cp, int cpu);
2624
void cpudl_cleanup(struct cpudl *cp);

kernel/sched/deadline.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1811,7 +1811,7 @@ static void dec_dl_deadline(struct dl_rq *dl_rq, u64 deadline)
18111811
if (!dl_rq->dl_nr_running) {
18121812
dl_rq->earliest_dl.curr = 0;
18131813
dl_rq->earliest_dl.next = 0;
1814-
cpudl_clear(&rq->rd->cpudl, rq->cpu);
1814+
cpudl_clear(&rq->rd->cpudl, rq->cpu, rq->online);
18151815
cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio.curr);
18161816
} else {
18171817
struct rb_node *leftmost = rb_first_cached(&dl_rq->root);
@@ -2883,9 +2883,10 @@ static void rq_online_dl(struct rq *rq)
28832883
if (rq->dl.overloaded)
28842884
dl_set_overload(rq);
28852885

2886-
cpudl_set_freecpu(&rq->rd->cpudl, rq->cpu);
28872886
if (rq->dl.dl_nr_running > 0)
28882887
cpudl_set(&rq->rd->cpudl, rq->cpu, rq->dl.earliest_dl.curr);
2888+
else
2889+
cpudl_clear(&rq->rd->cpudl, rq->cpu, true);
28892890
}
28902891

28912892
/* Assumes rq->lock is held */
@@ -2894,8 +2895,7 @@ static void rq_offline_dl(struct rq *rq)
28942895
if (rq->dl.overloaded)
28952896
dl_clear_overload(rq);
28962897

2897-
cpudl_clear(&rq->rd->cpudl, rq->cpu);
2898-
cpudl_clear_freecpu(&rq->rd->cpudl, rq->cpu);
2898+
cpudl_clear(&rq->rd->cpudl, rq->cpu, false);
28992899
}
29002900

29012901
void __init init_sched_dl_class(void)

0 commit comments

Comments
 (0)