Commit 4fc420c9 authored by Daisuke Nishimura's avatar Daisuke Nishimura Committed by Ingo Molnar

sched: Fix cgroup movement of forking process

There is a small race between task_fork_fair() and sched_move_task(),
which is trying to move the parent.

        task_fork_fair()                 sched_move_task()
--------------------------------+---------------------------------
  cfs_rq = task_cfs_rq(current)
    -> cfs_rq is the "old" one.
  curr = cfs_rq->curr
    -> curr is set to the parent.
                                    task_rq_lock()
                                    dequeue_task()
                                      ->parent.se.vruntime -= (old)cfs_rq->min_vruntime
                                    enqueue_task()
                                      ->parent.se.vruntime += (new)cfs_rq->min_vruntime
                                    task_rq_unlock()
  raw_spin_lock_irqsave(rq->lock)
  se->vruntime = curr->vruntime
    -> vruntime of the child is set to that of the parent
       which has already been updated by sched_move_task().
  se->vruntime -= (old)cfs_rq->min_vruntime.
  raw_spin_unlock_irqrestore(rq->lock)

As a result, vruntime of the child becomes far bigger than expected,
if (new)cfs_rq->min_vruntime >> (old)cfs_rq->min_vruntime.

This patch fixes this problem by setting "cfs_rq" and "curr" after
holding the rq->lock.
Signed-off-by: default avatarDaisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Acked-by: default avatarPaul Turner <pjt@google.com>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tejun Heo <tj@kernel.org>
Link: http://lkml.kernel.org/r/20111215143655.662676b0.nishimura@mxp.nes.nec.co.jpSigned-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 11534ec5
...@@ -5190,8 +5190,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) ...@@ -5190,8 +5190,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
*/ */
static void task_fork_fair(struct task_struct *p) static void task_fork_fair(struct task_struct *p)
{ {
struct cfs_rq *cfs_rq = task_cfs_rq(current); struct cfs_rq *cfs_rq;
struct sched_entity *se = &p->se, *curr = cfs_rq->curr; struct sched_entity *se = &p->se, *curr;
int this_cpu = smp_processor_id(); int this_cpu = smp_processor_id();
struct rq *rq = this_rq(); struct rq *rq = this_rq();
unsigned long flags; unsigned long flags;
...@@ -5200,6 +5200,9 @@ static void task_fork_fair(struct task_struct *p) ...@@ -5200,6 +5200,9 @@ static void task_fork_fair(struct task_struct *p)
update_rq_clock(rq); update_rq_clock(rq);
cfs_rq = task_cfs_rq(current);
curr = cfs_rq->curr;
if (unlikely(task_cpu(p) != this_cpu)) { if (unlikely(task_cpu(p) != this_cpu)) {
rcu_read_lock(); rcu_read_lock();
__set_task_cpu(p, this_cpu); __set_task_cpu(p, this_cpu);
......
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