Skip to content

Commit 73f39e4

Browse files
vingu-linaropundiramit
authored andcommitted
BACKPORT: sched/cgroup: Fix cpu_cgroup_fork() handling
A new fair task is detached and attached from/to task_group with: cgroup_post_fork() ss->fork(child) := cpu_cgroup_fork() sched_move_task() task_move_group_fair() Which is wrong, because at this point in fork() the task isn't fully initialized and it cannot 'move' to another group, because its not attached to any group as yet. In fact, cpu_cgroup_fork() needs a small part of sched_move_task() so we can just call this small part directly instead sched_move_task(). And the task doesn't really migrate because it is not yet attached so we need the following sequence: do_fork() sched_fork() __set_task_cpu() cgroup_post_fork() set_task_rq() # set task group and runqueue wake_up_new_task() select_task_rq() can select a new cpu __set_task_cpu post_init_entity_util_avg attach_task_cfs_rq() activate_task enqueue_task This patch makes that happen. BACKPORT: Difference from original commit: - Removed use of DEQUEUE_MOVE (which isn't defined in 4.4) in dequeue_task flags - Replaced "struct rq_flags rf" with "unsigned long flags". Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org> [ Added TASK_SET_GROUP to set depth properly. ] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org> (cherry picked from commit ea86cb4b7621e1298a37197005bf0abcc86348d4) Change-Id: I8126fd923288acf961218431ffd29d6bf6fd8d72 Signed-off-by: Brendan Jackman <brendan.jackman@arm.com> Signed-off-by: Chris Redpath <chris.redpath@arm.com>
1 parent b8cb776 commit 73f39e4

3 files changed

Lines changed: 67 additions & 24 deletions

File tree

kernel/sched/core.c

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8188,27 +8188,9 @@ void sched_offline_group(struct task_group *tg)
81888188
spin_unlock_irqrestore(&task_group_lock, flags);
81898189
}
81908190

8191-
/* change task's runqueue when it moves between groups.
8192-
* The caller of this function should have put the task in its new group
8193-
* by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
8194-
* reflect its new group.
8195-
*/
8196-
void sched_move_task(struct task_struct *tsk)
8191+
static void sched_change_group(struct task_struct *tsk, int type)
81978192
{
81988193
struct task_group *tg;
8199-
int queued, running;
8200-
unsigned long flags;
8201-
struct rq *rq;
8202-
8203-
rq = task_rq_lock(tsk, &flags);
8204-
8205-
running = task_current(rq, tsk);
8206-
queued = task_on_rq_queued(tsk);
8207-
8208-
if (queued)
8209-
dequeue_task(rq, tsk, DEQUEUE_SAVE);
8210-
if (unlikely(running))
8211-
put_prev_task(rq, tsk);
82128194

82138195
/*
82148196
* All callers are synchronized by task_rq_lock(); we do not use RCU
@@ -8221,11 +8203,37 @@ void sched_move_task(struct task_struct *tsk)
82218203
tsk->sched_task_group = tg;
82228204

82238205
#ifdef CONFIG_FAIR_GROUP_SCHED
8224-
if (tsk->sched_class->task_move_group)
8225-
tsk->sched_class->task_move_group(tsk);
8206+
if (tsk->sched_class->task_change_group)
8207+
tsk->sched_class->task_change_group(tsk, type);
82268208
else
82278209
#endif
82288210
set_task_rq(tsk, task_cpu(tsk));
8211+
}
8212+
8213+
/*
8214+
* Change task's runqueue when it moves between groups.
8215+
*
8216+
* The caller of this function should have put the task in its new group by
8217+
* now. This function just updates tsk->se.cfs_rq and tsk->se.parent to reflect
8218+
* its new group.
8219+
*/
8220+
void sched_move_task(struct task_struct *tsk)
8221+
{
8222+
int queued, running;
8223+
unsigned long flags;
8224+
struct rq *rq;
8225+
8226+
rq = task_rq_lock(tsk, &flags);
8227+
8228+
running = task_current(rq, tsk);
8229+
queued = task_on_rq_queued(tsk);
8230+
8231+
if (queued)
8232+
dequeue_task(rq, tsk, DEQUEUE_SAVE);
8233+
if (unlikely(running))
8234+
put_prev_task(rq, tsk);
8235+
8236+
sched_change_group(tsk, TASK_MOVE_GROUP);
82298237

82308238
if (unlikely(running))
82318239
tsk->sched_class->set_curr_task(rq);
@@ -8662,9 +8670,20 @@ static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
86628670
sched_free_group(tg);
86638671
}
86648672

8673+
/*
8674+
* This is called before wake_up_new_task(), therefore we really only
8675+
* have to set its group bits, all the other stuff does not apply.
8676+
*/
86658677
static void cpu_cgroup_fork(struct task_struct *task, void *private)
86668678
{
8667-
sched_move_task(task);
8679+
unsigned long flags;
8680+
struct rq *rq;
8681+
8682+
rq = task_rq_lock(task, &flags);
8683+
8684+
sched_change_group(task, TASK_SET_GROUP);
8685+
8686+
task_rq_unlock(rq, task, &flags);
86688687
}
86698688

86708689
static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)

kernel/sched/fair.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10119,6 +10119,14 @@ void init_cfs_rq(struct cfs_rq *cfs_rq)
1011910119
}
1012010120

1012110121
#ifdef CONFIG_FAIR_GROUP_SCHED
10122+
static void task_set_group_fair(struct task_struct *p)
10123+
{
10124+
struct sched_entity *se = &p->se;
10125+
10126+
set_task_rq(p, task_cpu(p));
10127+
se->depth = se->parent ? se->parent->depth + 1 : 0;
10128+
}
10129+
1012210130
static void task_move_group_fair(struct task_struct *p)
1012310131
{
1012410132
detach_task_cfs_rq(p);
@@ -10131,6 +10139,19 @@ static void task_move_group_fair(struct task_struct *p)
1013110139
attach_task_cfs_rq(p);
1013210140
}
1013310141

10142+
static void task_change_group_fair(struct task_struct *p, int type)
10143+
{
10144+
switch (type) {
10145+
case TASK_SET_GROUP:
10146+
task_set_group_fair(p);
10147+
break;
10148+
10149+
case TASK_MOVE_GROUP:
10150+
task_move_group_fair(p);
10151+
break;
10152+
}
10153+
}
10154+
1013410155
void free_fair_sched_group(struct task_group *tg)
1013510156
{
1013610157
int i;
@@ -10357,7 +10378,7 @@ const struct sched_class fair_sched_class = {
1035710378
.update_curr = update_curr_fair,
1035810379

1035910380
#ifdef CONFIG_FAIR_GROUP_SCHED
10360-
.task_move_group = task_move_group_fair,
10381+
.task_change_group = task_change_group_fair,
1036110382
#endif
1036210383
};
1036310384

kernel/sched/sched.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1293,8 +1293,11 @@ struct sched_class {
12931293

12941294
void (*update_curr) (struct rq *rq);
12951295

1296+
#define TASK_SET_GROUP 0
1297+
#define TASK_MOVE_GROUP 1
1298+
12961299
#ifdef CONFIG_FAIR_GROUP_SCHED
1297-
void (*task_move_group) (struct task_struct *p);
1300+
void (*task_change_group)(struct task_struct *p, int type);
12981301
#endif
12991302
};
13001303

0 commit comments

Comments
 (0)