Commit 713f0f37 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sched-urgent-2021-08-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull scheduler fix from Thomas Gleixner:
 "A single scheduler fix:

   - Prevent a double enqueue caused by rt_effective_prio() being
     invoked twice in __sched_setscheduler()"

* tag 'sched-urgent-2021-08-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  sched/rt: Fix double enqueue caused by rt_effective_prio
parents 74eedeba f558c2b8
...@@ -1981,12 +1981,18 @@ void deactivate_task(struct rq *rq, struct task_struct *p, int flags) ...@@ -1981,12 +1981,18 @@ void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
dequeue_task(rq, p, flags); dequeue_task(rq, p, flags);
} }
/* static inline int __normal_prio(int policy, int rt_prio, int nice)
* __normal_prio - return the priority that is based on the static prio
*/
static inline int __normal_prio(struct task_struct *p)
{ {
return p->static_prio; int prio;
if (dl_policy(policy))
prio = MAX_DL_PRIO - 1;
else if (rt_policy(policy))
prio = MAX_RT_PRIO - 1 - rt_prio;
else
prio = NICE_TO_PRIO(nice);
return prio;
} }
/* /*
...@@ -1998,15 +2004,7 @@ static inline int __normal_prio(struct task_struct *p) ...@@ -1998,15 +2004,7 @@ static inline int __normal_prio(struct task_struct *p)
*/ */
static inline int normal_prio(struct task_struct *p) static inline int normal_prio(struct task_struct *p)
{ {
int prio; return __normal_prio(p->policy, p->rt_priority, PRIO_TO_NICE(p->static_prio));
if (task_has_dl_policy(p))
prio = MAX_DL_PRIO-1;
else if (task_has_rt_policy(p))
prio = MAX_RT_PRIO-1 - p->rt_priority;
else
prio = __normal_prio(p);
return prio;
} }
/* /*
...@@ -4099,7 +4097,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) ...@@ -4099,7 +4097,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
} else if (PRIO_TO_NICE(p->static_prio) < 0) } else if (PRIO_TO_NICE(p->static_prio) < 0)
p->static_prio = NICE_TO_PRIO(0); p->static_prio = NICE_TO_PRIO(0);
p->prio = p->normal_prio = __normal_prio(p); p->prio = p->normal_prio = p->static_prio;
set_load_weight(p, false); set_load_weight(p, false);
/* /*
...@@ -6341,6 +6339,18 @@ int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flag ...@@ -6341,6 +6339,18 @@ int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flag
} }
EXPORT_SYMBOL(default_wake_function); EXPORT_SYMBOL(default_wake_function);
static void __setscheduler_prio(struct task_struct *p, int prio)
{
if (dl_prio(prio))
p->sched_class = &dl_sched_class;
else if (rt_prio(prio))
p->sched_class = &rt_sched_class;
else
p->sched_class = &fair_sched_class;
p->prio = prio;
}
#ifdef CONFIG_RT_MUTEXES #ifdef CONFIG_RT_MUTEXES
static inline int __rt_effective_prio(struct task_struct *pi_task, int prio) static inline int __rt_effective_prio(struct task_struct *pi_task, int prio)
...@@ -6456,22 +6466,19 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task) ...@@ -6456,22 +6466,19 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
} else { } else {
p->dl.pi_se = &p->dl; p->dl.pi_se = &p->dl;
} }
p->sched_class = &dl_sched_class;
} else if (rt_prio(prio)) { } else if (rt_prio(prio)) {
if (dl_prio(oldprio)) if (dl_prio(oldprio))
p->dl.pi_se = &p->dl; p->dl.pi_se = &p->dl;
if (oldprio < prio) if (oldprio < prio)
queue_flag |= ENQUEUE_HEAD; queue_flag |= ENQUEUE_HEAD;
p->sched_class = &rt_sched_class;
} else { } else {
if (dl_prio(oldprio)) if (dl_prio(oldprio))
p->dl.pi_se = &p->dl; p->dl.pi_se = &p->dl;
if (rt_prio(oldprio)) if (rt_prio(oldprio))
p->rt.timeout = 0; p->rt.timeout = 0;
p->sched_class = &fair_sched_class;
} }
p->prio = prio; __setscheduler_prio(p, prio);
if (queued) if (queued)
enqueue_task(rq, p, queue_flag); enqueue_task(rq, p, queue_flag);
...@@ -6824,35 +6831,6 @@ static void __setscheduler_params(struct task_struct *p, ...@@ -6824,35 +6831,6 @@ static void __setscheduler_params(struct task_struct *p,
set_load_weight(p, true); set_load_weight(p, true);
} }
/* Actually do priority change: must hold pi & rq lock. */
static void __setscheduler(struct rq *rq, struct task_struct *p,
const struct sched_attr *attr, bool keep_boost)
{
/*
* If params can't change scheduling class changes aren't allowed
* either.
*/
if (attr->sched_flags & SCHED_FLAG_KEEP_PARAMS)
return;
__setscheduler_params(p, attr);
/*
* Keep a potential priority boosting if called from
* sched_setscheduler().
*/
p->prio = normal_prio(p);
if (keep_boost)
p->prio = rt_effective_prio(p, p->prio);
if (dl_prio(p->prio))
p->sched_class = &dl_sched_class;
else if (rt_prio(p->prio))
p->sched_class = &rt_sched_class;
else
p->sched_class = &fair_sched_class;
}
/* /*
* Check the target process has a UID that matches the current process's: * Check the target process has a UID that matches the current process's:
*/ */
...@@ -6873,10 +6851,8 @@ static int __sched_setscheduler(struct task_struct *p, ...@@ -6873,10 +6851,8 @@ static int __sched_setscheduler(struct task_struct *p,
const struct sched_attr *attr, const struct sched_attr *attr,
bool user, bool pi) bool user, bool pi)
{ {
int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 : int oldpolicy = -1, policy = attr->sched_policy;
MAX_RT_PRIO - 1 - attr->sched_priority; int retval, oldprio, newprio, queued, running;
int retval, oldprio, oldpolicy = -1, queued, running;
int new_effective_prio, policy = attr->sched_policy;
const struct sched_class *prev_class; const struct sched_class *prev_class;
struct callback_head *head; struct callback_head *head;
struct rq_flags rf; struct rq_flags rf;
...@@ -7074,6 +7050,7 @@ static int __sched_setscheduler(struct task_struct *p, ...@@ -7074,6 +7050,7 @@ static int __sched_setscheduler(struct task_struct *p,
p->sched_reset_on_fork = reset_on_fork; p->sched_reset_on_fork = reset_on_fork;
oldprio = p->prio; oldprio = p->prio;
newprio = __normal_prio(policy, attr->sched_priority, attr->sched_nice);
if (pi) { if (pi) {
/* /*
* Take priority boosted tasks into account. If the new * Take priority boosted tasks into account. If the new
...@@ -7082,8 +7059,8 @@ static int __sched_setscheduler(struct task_struct *p, ...@@ -7082,8 +7059,8 @@ static int __sched_setscheduler(struct task_struct *p,
* the runqueue. This will be done when the task deboost * the runqueue. This will be done when the task deboost
* itself. * itself.
*/ */
new_effective_prio = rt_effective_prio(p, newprio); newprio = rt_effective_prio(p, newprio);
if (new_effective_prio == oldprio) if (newprio == oldprio)
queue_flags &= ~DEQUEUE_MOVE; queue_flags &= ~DEQUEUE_MOVE;
} }
...@@ -7096,7 +7073,10 @@ static int __sched_setscheduler(struct task_struct *p, ...@@ -7096,7 +7073,10 @@ static int __sched_setscheduler(struct task_struct *p,
prev_class = p->sched_class; prev_class = p->sched_class;
__setscheduler(rq, p, attr, pi); if (!(attr->sched_flags & SCHED_FLAG_KEEP_PARAMS)) {
__setscheduler_params(p, attr);
__setscheduler_prio(p, newprio);
}
__setscheduler_uclamp(p, attr); __setscheduler_uclamp(p, attr);
if (queued) { if (queued) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment