[PATCH 2/2] sched/deadline: Temporary copy static parameters to boosted non-DEADLINE entities

From: Juri Lelli
Date: Tue Nov 12 2019 - 02:51:22 EST


Boosted entities (Priority Inheritance) use static DEADLINE parameters
of the top priority waiter. However, there might be cases where top
waiter could be a non-DEADLINE entity that is currently boosted by a
DEADLINE entity from a different lock chain (i.e., nested priority
chains involving entities of non-DEADLINE classes). In this case, top
waiter static DEADLINE parameters could null (initialized to 0 at
fork()) and replenish_dl_entity() would hit a BUG().

Fix this by temporarily copying static DEADLINE parameters of top
DEADLINE waiter (there must be at least one in the chain(s) for the
problem above to happen) into boosted entities. Parameters are reset
during deboost.

Reported-by: Glenn Elliott <glenn@xxxxxxxxxxx>
Signed-off-by: Juri Lelli <juri.lelli@xxxxxxxxxx>
---
kernel/sched/core.c | 6 ++++--
kernel/sched/deadline.c | 17 +++++++++++++++++
kernel/sched/sched.h | 1 +
3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 7880f4f64d0e..a3eb57cfcfb4 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4441,19 +4441,21 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
if (!dl_prio(p->normal_prio) ||
(pi_task && dl_entity_preempt(&pi_task->dl, &p->dl))) {
p->dl.dl_boosted = 1;
+ if (!dl_prio(p->normal_prio))
+ __dl_copy_static(p, pi_task);
queue_flag |= ENQUEUE_REPLENISH;
} else
p->dl.dl_boosted = 0;
p->sched_class = &dl_sched_class;
} else if (rt_prio(prio)) {
if (dl_prio(oldprio))
- p->dl.dl_boosted = 0;
+ __dl_clear_params(p);
if (oldprio < prio)
queue_flag |= ENQUEUE_HEAD;
p->sched_class = &rt_sched_class;
} else {
if (dl_prio(oldprio))
- p->dl.dl_boosted = 0;
+ __dl_clear_params(p);
if (rt_prio(oldprio))
p->rt.timeout = 0;
p->sched_class = &fair_sched_class;
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 951a7b44156f..a823391b245e 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -2676,6 +2676,22 @@ bool __checkparam_dl(const struct sched_attr *attr)
return true;
}

+/*
+ * This function clears the sched_dl_entity static params.
+ */
+void __dl_copy_static(struct task_struct *to, struct task_struct *from)
+{
+ struct sched_dl_entity *to_se = &to->dl;
+ struct sched_dl_entity *from_se = &from->dl;
+
+ to_se->dl_runtime = from_se->dl_runtime;
+ to_se->dl_deadline = from_se->dl_deadline;
+ to_se->dl_period = from_se->dl_period;
+ to_se->flags = from_se->flags;
+ to_se->dl_bw = from_se->dl_bw;
+ to_se->dl_density = from_se->dl_density;
+}
+
/*
* This function clears the sched_dl_entity static params.
*/
@@ -2690,6 +2706,7 @@ void __dl_clear_params(struct task_struct *p)
dl_se->dl_bw = 0;
dl_se->dl_density = 0;

+ dl_se->dl_boosted = 0;
dl_se->dl_throttled = 0;
dl_se->dl_yielded = 0;
dl_se->dl_non_contending = 0;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 0db2c1b3361e..92444306fff7 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -239,6 +239,7 @@ struct rt_bandwidth {
unsigned int rt_period_active;
};

+void __dl_copy_static(struct task_struct *to, struct task_struct *from);
void __dl_clear_params(struct task_struct *p);

/*
--
2.17.2