aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-02-07 14:58:42 -0500
committerIngo Molnar <mingo@kernel.org>2014-02-22 12:10:04 -0500
commitc365c292d05908c6ea6f32708f331e21033fe71d (patch)
treefcaf27f6d0296ef48203f940d1ed9d8c02c56860
parent81a44c5441d7f7d2c3dc9105f4d65ad0d5818617 (diff)
sched: Consider pi boosting in setscheduler()
If a PI boosted task policy/priority is modified by a setscheduler() call we unconditionally dequeue and requeue the task if it is on the runqueue even if the new priority is lower than the current effective boosted priority. This can result in undesired reordering of the priority bucket list. If the new priority is less or equal than the current effective we just store the new parameters in the task struct and leave the scheduler class and the runqueue untouched. This is handled when the task deboosts itself. Only if the new priority is higher than the effective boosted priority we apply the change immediately. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> [ Rebase ontop of v3.14-rc1. ] Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Dario Faggioli <raistlin@linux.it> Signed-off-by: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1391803122-4425-7-git-send-email-bigeasy@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/sched/rt.h7
-rw-r--r--kernel/locking/rtmutex.c12
-rw-r--r--kernel/sched/core.c41
3 files changed, 49 insertions, 11 deletions
diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h
index f7453d4c5613..6341f5be6e24 100644
--- a/include/linux/sched/rt.h
+++ b/include/linux/sched/rt.h
@@ -18,6 +18,7 @@ static inline int rt_task(struct task_struct *p)
18#ifdef CONFIG_RT_MUTEXES 18#ifdef CONFIG_RT_MUTEXES
19extern int rt_mutex_getprio(struct task_struct *p); 19extern int rt_mutex_getprio(struct task_struct *p);
20extern void rt_mutex_setprio(struct task_struct *p, int prio); 20extern void rt_mutex_setprio(struct task_struct *p, int prio);
21extern int rt_mutex_check_prio(struct task_struct *task, int newprio);
21extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task); 22extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task);
22extern void rt_mutex_adjust_pi(struct task_struct *p); 23extern void rt_mutex_adjust_pi(struct task_struct *p);
23static inline bool tsk_is_pi_blocked(struct task_struct *tsk) 24static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
@@ -29,6 +30,12 @@ static inline int rt_mutex_getprio(struct task_struct *p)
29{ 30{
30 return p->normal_prio; 31 return p->normal_prio;
31} 32}
33
34static inline int rt_mutex_check_prio(struct task_struct *task, int newprio)
35{
36 return 0;
37}
38
32static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task) 39static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
33{ 40{
34 return NULL; 41 return NULL;
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index 2e960a2bab81..aa4dff04b594 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -213,6 +213,18 @@ struct task_struct *rt_mutex_get_top_task(struct task_struct *task)
213} 213}
214 214
215/* 215/*
216 * Called by sched_setscheduler() to check whether the priority change
217 * is overruled by a possible priority boosting.
218 */
219int rt_mutex_check_prio(struct task_struct *task, int newprio)
220{
221 if (!task_has_pi_waiters(task))
222 return 0;
223
224 return task_top_pi_waiter(task)->task->prio <= newprio;
225}
226
227/*
216 * Adjust the priority of a task, after its pi_waiters got modified. 228 * Adjust the priority of a task, after its pi_waiters got modified.
217 * 229 *
218 * This can be both boosting and unboosting. task->pi_lock must be held. 230 * This can be both boosting and unboosting. task->pi_lock must be held.
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 9c2fcbf9a266..003263b3b05c 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2902,7 +2902,8 @@ EXPORT_SYMBOL(sleep_on_timeout);
2902 * This function changes the 'effective' priority of a task. It does 2902 * This function changes the 'effective' priority of a task. It does
2903 * not touch ->normal_prio like __setscheduler(). 2903 * not touch ->normal_prio like __setscheduler().
2904 * 2904 *
2905 * Used by the rt_mutex code to implement priority inheritance logic. 2905 * Used by the rt_mutex code to implement priority inheritance
2906 * logic. Call site only calls if the priority of the task changed.
2906 */ 2907 */
2907void rt_mutex_setprio(struct task_struct *p, int prio) 2908void rt_mutex_setprio(struct task_struct *p, int prio)
2908{ 2909{
@@ -3171,9 +3172,8 @@ __setparam_dl(struct task_struct *p, const struct sched_attr *attr)
3171 dl_se->dl_new = 1; 3172 dl_se->dl_new = 1;
3172} 3173}
3173 3174
3174/* Actually do priority change: must hold pi & rq lock. */ 3175static void __setscheduler_params(struct task_struct *p,
3175static void __setscheduler(struct rq *rq, struct task_struct *p, 3176 const struct sched_attr *attr)
3176 const struct sched_attr *attr)
3177{ 3177{
3178 int policy = attr->sched_policy; 3178 int policy = attr->sched_policy;
3179 3179
@@ -3193,9 +3193,14 @@ static void __setscheduler(struct rq *rq, struct task_struct *p,
3193 * getparam()/getattr() don't report silly values for !rt tasks. 3193 * getparam()/getattr() don't report silly values for !rt tasks.
3194 */ 3194 */
3195 p->rt_priority = attr->sched_priority; 3195 p->rt_priority = attr->sched_priority;
3196 set_load_weight(p);
3197}
3196 3198
3197 p->normal_prio = normal_prio(p); 3199/* Actually do priority change: must hold pi & rq lock. */
3198 p->prio = rt_mutex_getprio(p); 3200static void __setscheduler(struct rq *rq, struct task_struct *p,
3201 const struct sched_attr *attr)
3202{
3203 __setscheduler_params(p, attr);
3199 3204
3200 if (dl_prio(p->prio)) 3205 if (dl_prio(p->prio))
3201 p->sched_class = &dl_sched_class; 3206 p->sched_class = &dl_sched_class;
@@ -3203,8 +3208,6 @@ static void __setscheduler(struct rq *rq, struct task_struct *p,
3203 p->sched_class = &rt_sched_class; 3208 p->sched_class = &rt_sched_class;
3204 else 3209 else
3205 p->sched_class = &fair_sched_class; 3210 p->sched_class = &fair_sched_class;
3206
3207 set_load_weight(p);
3208} 3211}
3209 3212
3210static void 3213static void
@@ -3257,6 +3260,7 @@ static int __sched_setscheduler(struct task_struct *p,
3257 const struct sched_attr *attr, 3260 const struct sched_attr *attr,
3258 bool user) 3261 bool user)
3259{ 3262{
3263 int newprio = MAX_RT_PRIO - 1 - attr->sched_priority;
3260 int retval, oldprio, oldpolicy = -1, on_rq, running; 3264 int retval, oldprio, oldpolicy = -1, on_rq, running;
3261 int policy = attr->sched_policy; 3265 int policy = attr->sched_policy;
3262 unsigned long flags; 3266 unsigned long flags;
@@ -3427,6 +3431,24 @@ change:
3427 return -EBUSY; 3431 return -EBUSY;
3428 } 3432 }
3429 3433
3434 p->sched_reset_on_fork = reset_on_fork;
3435 oldprio = p->prio;
3436
3437 /*
3438 * Special case for priority boosted tasks.
3439 *
3440 * If the new priority is lower or equal (user space view)
3441 * than the current (boosted) priority, we just store the new
3442 * normal parameters and do not touch the scheduler class and
3443 * the runqueue. This will be done when the task deboost
3444 * itself.
3445 */
3446 if (rt_mutex_check_prio(p, newprio)) {
3447 __setscheduler_params(p, attr);
3448 task_rq_unlock(rq, p, &flags);
3449 return 0;
3450 }
3451
3430 on_rq = p->on_rq; 3452 on_rq = p->on_rq;
3431 running = task_current(rq, p); 3453 running = task_current(rq, p);
3432 if (on_rq) 3454 if (on_rq)
@@ -3434,9 +3456,6 @@ change:
3434 if (running) 3456 if (running)
3435 p->sched_class->put_prev_task(rq, p); 3457 p->sched_class->put_prev_task(rq, p);
3436 3458
3437 p->sched_reset_on_fork = reset_on_fork;
3438
3439 oldprio = p->prio;
3440 prev_class = p->sched_class; 3459 prev_class = p->sched_class;
3441 __setscheduler(rq, p, attr); 3460 __setscheduler(rq, p, attr);
3442 3461