diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2007-11-15 14:57:40 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2007-11-15 14:57:40 -0500 |
commit | dae51f56204d33444f61d9e7af3ee70aef55daa4 (patch) | |
tree | 586c209c5b46da902dff912fa96e797840198030 /kernel/sched.c | |
parent | 9778385db35a799d410039be123044a0d3e917a2 (diff) |
sched: fix SCHED_FIFO tasks & FAIR_GROUP_SCHED
Suppose that the SCHED_FIFO task does
switch_uid(new_user);
Now, p->se.cfs_rq and p->se.parent both point into the old
user_struct->tg because sched_move_task() doesn't call set_task_cfs_rq()
for !fair_sched_class case.
Suppose that old user_struct/task_group is freed/reused, and the task
does
sched_setscheduler(SCHED_NORMAL);
__setscheduler() sets fair_sched_class, but doesn't update
->se.cfs_rq/parent which point to the freed memory.
This means that check_preempt_wakeup() doing
while (!is_same_group(se, pse)) {
se = parent_entity(se);
pse = parent_entity(pse);
}
may OOPS in a similar way if rq->curr or p did something like above.
Perhaps we need something like the patch below, note that
__setscheduler() can't do set_task_cfs_rq().
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 908335e1781a..d62b759753f3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -7087,8 +7087,10 @@ void sched_move_task(struct task_struct *tsk) | |||
7087 | 7087 | ||
7088 | rq = task_rq_lock(tsk, &flags); | 7088 | rq = task_rq_lock(tsk, &flags); |
7089 | 7089 | ||
7090 | if (tsk->sched_class != &fair_sched_class) | 7090 | if (tsk->sched_class != &fair_sched_class) { |
7091 | set_task_cfs_rq(tsk); | ||
7091 | goto done; | 7092 | goto done; |
7093 | } | ||
7092 | 7094 | ||
7093 | update_rq_clock(rq); | 7095 | update_rq_clock(rq); |
7094 | 7096 | ||