| From a77dfb9d34d1679ea857b18c980dc03399b4b90e Mon Sep 17 00:00:00 2001 |
| From: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| Date: Thu, 10 Feb 2011 10:23:28 +0100 |
| Subject: sched, cgroup: Fixup broken cgroup movement |
| |
| Commit: b2b5ce022acf5e9f52f7b78c5579994fdde191d4 upstream |
| |
| Dima noticed that we fail to correct the ->vruntime of sleeping tasks |
| when we move them between cgroups. |
| |
| Reported-by: Dima Zavin <dima@android.com> |
| Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| Tested-by: Mike Galbraith <efault@gmx.de> |
| LKML-Reference: <1287150604.29097.1513.camel@twins> |
| Signed-off-by: Ingo Molnar <mingo@elte.hu> |
| Signed-off-by: Mike Galbraith <efault@gmx.de> |
| Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| include/linux/sched.h | 2 +- |
| kernel/sched.c | 8 ++++---- |
| kernel/sched_fair.c | 25 +++++++++++++++++++------ |
| 3 files changed, 24 insertions(+), 11 deletions(-) |
| |
| --- a/include/linux/sched.h |
| +++ b/include/linux/sched.h |
| @@ -1113,7 +1113,7 @@ struct sched_class { |
| struct task_struct *task); |
| |
| #ifdef CONFIG_FAIR_GROUP_SCHED |
| - void (*moved_group) (struct task_struct *p, int on_rq); |
| + void (*task_move_group) (struct task_struct *p, int on_rq); |
| #endif |
| }; |
| |
| --- a/kernel/sched.c |
| +++ b/kernel/sched.c |
| @@ -10224,12 +10224,12 @@ void sched_move_task(struct task_struct |
| if (unlikely(running)) |
| tsk->sched_class->put_prev_task(rq, tsk); |
| |
| - set_task_rq(tsk, task_cpu(tsk)); |
| - |
| #ifdef CONFIG_FAIR_GROUP_SCHED |
| - if (tsk->sched_class->moved_group) |
| - tsk->sched_class->moved_group(tsk, on_rq); |
| + if (tsk->sched_class->task_move_group) |
| + tsk->sched_class->task_move_group(tsk, on_rq); |
| + else |
| #endif |
| + set_task_rq(tsk, task_cpu(tsk)); |
| |
| if (unlikely(running)) |
| tsk->sched_class->set_curr_task(rq); |
| --- a/kernel/sched_fair.c |
| +++ b/kernel/sched_fair.c |
| @@ -2068,13 +2068,26 @@ static void set_curr_task_fair(struct rq |
| } |
| |
| #ifdef CONFIG_FAIR_GROUP_SCHED |
| -static void moved_group_fair(struct task_struct *p, int on_rq) |
| +static void task_move_group_fair(struct task_struct *p, int on_rq) |
| { |
| - struct cfs_rq *cfs_rq = task_cfs_rq(p); |
| - |
| - update_curr(cfs_rq); |
| + /* |
| + * If the task was not on the rq at the time of this cgroup movement |
| + * it must have been asleep, sleeping tasks keep their ->vruntime |
| + * absolute on their old rq until wakeup (needed for the fair sleeper |
| + * bonus in place_entity()). |
| + * |
| + * If it was on the rq, we've just 'preempted' it, which does convert |
| + * ->vruntime to a relative base. |
| + * |
| + * Make sure both cases convert their relative position when migrating |
| + * to another cgroup's rq. This does somewhat interfere with the |
| + * fair sleeper stuff for the first placement, but who cares. |
| + */ |
| + if (!on_rq) |
| + p->se.vruntime -= cfs_rq_of(&p->se)->min_vruntime; |
| + set_task_rq(p, task_cpu(p)); |
| if (!on_rq) |
| - place_entity(cfs_rq, &p->se, 1); |
| + p->se.vruntime += cfs_rq_of(&p->se)->min_vruntime; |
| } |
| #endif |
| |
| @@ -2128,7 +2141,7 @@ static const struct sched_class fair_sch |
| .get_rr_interval = get_rr_interval_fair, |
| |
| #ifdef CONFIG_FAIR_GROUP_SCHED |
| - .moved_group = moved_group_fair, |
| + .task_move_group = task_move_group_fair, |
| #endif |
| }; |
| |