diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2010-02-17 03:05:48 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-15 12:07:14 -0400 |
commit | 371f1d177527b1f815b55a03284ccb2c6dc79c3a (patch) | |
tree | 206f58979b6b9df3a4f0caa473c1b4703bb84fd5 | |
parent | 51c80d13a1d86848e178a5a5ea31cb0edfeb3efe (diff) |
sched: Don't use possibly stale sched_class
commit 83ab0aa0d5623d823444db82c3b3c34d7ec364ae upstream.
setscheduler() saves task->sched_class outside of the rq->lock held
region for a check after the setscheduler changes have become
effective. That might result in checking a stale value.
rtmutex_setprio() has the same problem, though it is protected by
p->pi_lock against setscheduler(), but for correctness sake (and to
avoid bad examples) it needs to be fixed as well.
Retrieve task->sched_class inside of the rq->lock held region.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | kernel/sched.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index e4b69fae2f33..00a59b090e6f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -6065,7 +6065,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) | |||
6065 | unsigned long flags; | 6065 | unsigned long flags; |
6066 | int oldprio, on_rq, running; | 6066 | int oldprio, on_rq, running; |
6067 | struct rq *rq; | 6067 | struct rq *rq; |
6068 | const struct sched_class *prev_class = p->sched_class; | 6068 | const struct sched_class *prev_class; |
6069 | 6069 | ||
6070 | BUG_ON(prio < 0 || prio > MAX_PRIO); | 6070 | BUG_ON(prio < 0 || prio > MAX_PRIO); |
6071 | 6071 | ||
@@ -6073,6 +6073,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) | |||
6073 | update_rq_clock(rq); | 6073 | update_rq_clock(rq); |
6074 | 6074 | ||
6075 | oldprio = p->prio; | 6075 | oldprio = p->prio; |
6076 | prev_class = p->sched_class; | ||
6076 | on_rq = p->se.on_rq; | 6077 | on_rq = p->se.on_rq; |
6077 | running = task_current(rq, p); | 6078 | running = task_current(rq, p); |
6078 | if (on_rq) | 6079 | if (on_rq) |
@@ -6292,7 +6293,7 @@ static int __sched_setscheduler(struct task_struct *p, int policy, | |||
6292 | { | 6293 | { |
6293 | int retval, oldprio, oldpolicy = -1, on_rq, running; | 6294 | int retval, oldprio, oldpolicy = -1, on_rq, running; |
6294 | unsigned long flags; | 6295 | unsigned long flags; |
6295 | const struct sched_class *prev_class = p->sched_class; | 6296 | const struct sched_class *prev_class; |
6296 | struct rq *rq; | 6297 | struct rq *rq; |
6297 | int reset_on_fork; | 6298 | int reset_on_fork; |
6298 | 6299 | ||
@@ -6406,6 +6407,7 @@ recheck: | |||
6406 | p->sched_reset_on_fork = reset_on_fork; | 6407 | p->sched_reset_on_fork = reset_on_fork; |
6407 | 6408 | ||
6408 | oldprio = p->prio; | 6409 | oldprio = p->prio; |
6410 | prev_class = p->sched_class; | ||
6409 | __setscheduler(rq, p, policy, param->sched_priority); | 6411 | __setscheduler(rq, p, policy, param->sched_priority); |
6410 | 6412 | ||
6411 | if (running) | 6413 | if (running) |