task_cpu() is often used on SCHED_DEADLINE to access the root_domain and associated information. However, the task_cpu() does not always reflect the correct CPU. The reason being is shown in the code: >From kernel/sched/core: ----- %< ----- * p->on_rq <- { 0, 1 = TASK_ON_RQ_QUEUED, 2 = TASK_ON_RQ_MIGRATING }: * * is set by activate_task() and cleared by deactivate_task(), under * rq->lock. Non-zero indicates the task is runnable, the special * ON_RQ_MIGRATING state is used for migration without holding both * rq->locks. It indicates task_cpu() is not stable, see task_rq_lock(). [...] * task_cpu(p): is changed by set_task_cpu(), the rules are: * * - Don't call set_task_cpu() on a blocked task: * * We don't care what CPU we're not running on, this simplifies hotplug, * the CPU assignment of blocked tasks isn't required to be valid. ----- >% ----- So, a sleeping task will not have its task_cpu() stable, and this is causing problems on SCHED_DEADLINE. In preparation for fixing this problems, we need to add helper functions that return the dl_task_cpu, root_domain, and "root" dl_bw that reflects the current placement/affinity of the task. Note that these functions are only required on the code path that can happen when the task is not queued. Signed-off-by: Daniel Bristot de Oliveira <bristot@xxxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Juri Lelli <juri.lelli@xxxxxxxxxx> Cc: Vincent Guittot <vincent.guittot@xxxxxxxxxx> Cc: Dietmar Eggemann <dietmar.eggemann@xxxxxxx> Cc: Steven Rostedt <rostedt@xxxxxxxxxxx> Cc: Ben Segall <bsegall@xxxxxxxxxx> Cc: Mel Gorman <mgorman@xxxxxxx> Cc: Daniel Bristot de Oliveira <bristot@xxxxxxxxxx> Cc: Li Zefan <lizefan@xxxxxxxxxx> Cc: Tejun Heo <tj@xxxxxxxxxx> Cc: Johannes Weiner <hannes@xxxxxxxxxxx> Cc: Valentin Schneider <valentin.schneider@xxxxxxx> Cc: linux-kernel@xxxxxxxxxxxxxxx Cc: cgroups@xxxxxxxxxxxxxxx --- kernel/sched/sched.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 54881d99cebd..5f3f3cb5a6ff 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2393,6 +2393,37 @@ void __dl_update(struct dl_bw *dl_b, s64 bw) rq->dl.extra_bw += bw; } } + +static inline +int dl_task_cpu(struct task_struct *p) +{ + /* + * We can only rely on task_cpu() of runnable tasks. + */ + if (p->on_rq) + return task_cpu(p); + + /* + * The task_cpu() of non-runnable task migth be pointing a CPU + * it cannot run anymore (see set_task_cpu()). Hence, let's + * get a possible cpu from the current cpu_mask. + */ + return cpumask_any(p->cpus_ptr); + +} + +static inline +struct root_domain *dl_task_rd(struct task_struct *p) +{ + int cpu = dl_task_cpu(p); + return cpu_rq(cpu)->rd; +} + +static inline +struct dl_bw *dl_task_root_bw(struct task_struct *p) +{ + return &dl_task_rd(p)->dl_bw; +} #else static inline void __dl_update(struct dl_bw *dl_b, s64 bw) @@ -2401,6 +2432,18 @@ void __dl_update(struct dl_bw *dl_b, s64 bw) dl->extra_bw += bw; } + +static inline +int dl_task_cpu(struct task_struct *p) +{ + return 0; +} + +static inline +struct dl_bw *dl_task_root_bw(struct task_struct *p) +{ + return &task_rq(p)->dl.dl_bw; +} #endif -- 2.29.2