Commit 6fe1f348 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

sched/cgroup: Fix cgroup entity load tracking tear-down

When a cgroup's CPU runqueue is destroyed, it should remove its
remaining load accounting from its parent cgroup.

The current site for doing so it unsuited because its far too late and
unordered against other cgroup removal (->css_free() will be, but we're also
in an RCU callback).

Put it in the ->css_offline() callback, which is the start of cgroup
destruction, right after the group has been made unavailable to
userspace. The ->css_offline() callbacks are called in hierarchical order
after the following v4.4 commit:

  aa226ff4 ("cgroup: make sure a parent css isn't offlined before its children")
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160121212416.GL6357@twins.programming.kicks-ass.netSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent fc77dbd3
...@@ -7860,11 +7860,9 @@ void sched_destroy_group(struct task_group *tg) ...@@ -7860,11 +7860,9 @@ void sched_destroy_group(struct task_group *tg)
void sched_offline_group(struct task_group *tg) void sched_offline_group(struct task_group *tg)
{ {
unsigned long flags; unsigned long flags;
int i;
/* end participation in shares distribution */ /* end participation in shares distribution */
for_each_possible_cpu(i) unregister_fair_sched_group(tg);
unregister_fair_sched_group(tg, i);
spin_lock_irqsave(&task_group_lock, flags); spin_lock_irqsave(&task_group_lock, flags);
list_del_rcu(&tg->list); list_del_rcu(&tg->list);
......
...@@ -8234,11 +8234,8 @@ void free_fair_sched_group(struct task_group *tg) ...@@ -8234,11 +8234,8 @@ void free_fair_sched_group(struct task_group *tg)
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
if (tg->cfs_rq) if (tg->cfs_rq)
kfree(tg->cfs_rq[i]); kfree(tg->cfs_rq[i]);
if (tg->se) { if (tg->se)
if (tg->se[i])
remove_entity_load_avg(tg->se[i]);
kfree(tg->se[i]); kfree(tg->se[i]);
}
} }
kfree(tg->cfs_rq); kfree(tg->cfs_rq);
...@@ -8286,21 +8283,29 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) ...@@ -8286,21 +8283,29 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
return 0; return 0;
} }
void unregister_fair_sched_group(struct task_group *tg, int cpu) void unregister_fair_sched_group(struct task_group *tg)
{ {
struct rq *rq = cpu_rq(cpu);
unsigned long flags; unsigned long flags;
struct rq *rq;
int cpu;
/* for_each_possible_cpu(cpu) {
* Only empty task groups can be destroyed; so we can speculatively if (tg->se[cpu])
* check on_list without danger of it being re-added. remove_entity_load_avg(tg->se[cpu]);
*/
if (!tg->cfs_rq[cpu]->on_list)
return;
raw_spin_lock_irqsave(&rq->lock, flags); /*
list_del_leaf_cfs_rq(tg->cfs_rq[cpu]); * Only empty task groups can be destroyed; so we can speculatively
raw_spin_unlock_irqrestore(&rq->lock, flags); * check on_list without danger of it being re-added.
*/
if (!tg->cfs_rq[cpu]->on_list)
continue;
rq = cpu_rq(cpu);
raw_spin_lock_irqsave(&rq->lock, flags);
list_del_leaf_cfs_rq(tg->cfs_rq[cpu]);
raw_spin_unlock_irqrestore(&rq->lock, flags);
}
} }
void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq, void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
...@@ -8382,7 +8387,7 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) ...@@ -8382,7 +8387,7 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
return 1; return 1;
} }
void unregister_fair_sched_group(struct task_group *tg, int cpu) { } void unregister_fair_sched_group(struct task_group *tg) { }
#endif /* CONFIG_FAIR_GROUP_SCHED */ #endif /* CONFIG_FAIR_GROUP_SCHED */
......
...@@ -313,7 +313,7 @@ extern int tg_nop(struct task_group *tg, void *data); ...@@ -313,7 +313,7 @@ extern int tg_nop(struct task_group *tg, void *data);
extern void free_fair_sched_group(struct task_group *tg); extern void free_fair_sched_group(struct task_group *tg);
extern int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent); extern int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent);
extern void unregister_fair_sched_group(struct task_group *tg, int cpu); extern void unregister_fair_sched_group(struct task_group *tg);
extern void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq, extern void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
struct sched_entity *se, int cpu, struct sched_entity *se, int cpu,
struct sched_entity *parent); struct sched_entity *parent);
......
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