diff options
| author | Li Zefan <lizefan@huawei.com> | 2013-01-24 14:30:48 +0800 | 
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2013-01-24 12:05:18 -0800 | 
| commit | ace783b9bbfa2182b4a561498db3f09a0c56bc79 (patch) | |
| tree | e490b561cbd0d14f6514f4f2cf1413bcab05c275 /kernel/sched/core.c | |
| parent | fe1c06ca7523baa668c1eaf1e1016fa64753c32e (diff) | |
| download | olio-linux-3.10-ace783b9bbfa2182b4a561498db3f09a0c56bc79.tar.xz olio-linux-3.10-ace783b9bbfa2182b4a561498db3f09a0c56bc79.zip  | |
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
  no ss->css_offline()
diput()
  syncornize_rcu()
  ss->css_free()       <-- unregister tg, and free it via call_rcu()
  kfree_rcu(cgroup)    <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
  ss->css_offline()    <-- unregister tg
diput()
  synchronize_rcu()    <-- wait possible refs to tg and cgroup
  ss->css_free()       <-- free tg
  kfree_rcu(cgroup)    <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/sched/core.c')
| -rw-r--r-- | kernel/sched/core.c | 49 | 
1 files changed, 39 insertions, 10 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 257002c13bb..106167243d6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7159,7 +7159,6 @@ static void free_sched_group(struct task_group *tg)  struct task_group *sched_create_group(struct task_group *parent)  {  	struct task_group *tg; -	unsigned long flags;  	tg = kzalloc(sizeof(*tg), GFP_KERNEL);  	if (!tg) @@ -7171,6 +7170,17 @@ struct task_group *sched_create_group(struct task_group *parent)  	if (!alloc_rt_sched_group(tg, parent))  		goto err; +	return tg; + +err: +	free_sched_group(tg); +	return ERR_PTR(-ENOMEM); +} + +void sched_online_group(struct task_group *tg, struct task_group *parent) +{ +	unsigned long flags; +  	spin_lock_irqsave(&task_group_lock, flags);  	list_add_rcu(&tg->list, &task_groups); @@ -7180,12 +7190,6 @@ struct task_group *sched_create_group(struct task_group *parent)  	INIT_LIST_HEAD(&tg->children);  	list_add_rcu(&tg->siblings, &parent->children);  	spin_unlock_irqrestore(&task_group_lock, flags); - -	return tg; - -err: -	free_sched_group(tg); -	return ERR_PTR(-ENOMEM);  }  /* rcu callback to free various structures associated with a task group */ @@ -7198,6 +7202,12 @@ static void free_sched_group_rcu(struct rcu_head *rhp)  /* Destroy runqueue etc associated with a task group */  void sched_destroy_group(struct task_group *tg)  { +	/* wait for possible concurrent references to cfs_rqs complete */ +	call_rcu(&tg->rcu, free_sched_group_rcu); +} + +void sched_offline_group(struct task_group *tg) +{  	unsigned long flags;  	int i; @@ -7209,9 +7219,6 @@ void sched_destroy_group(struct task_group *tg)  	list_del_rcu(&tg->list);  	list_del_rcu(&tg->siblings);  	spin_unlock_irqrestore(&task_group_lock, flags); - -	/* wait for possible concurrent references to cfs_rqs complete */ -	call_rcu(&tg->rcu, free_sched_group_rcu);  }  /* change task's runqueue when it moves between groups. @@ -7563,6 +7570,19 @@ static struct cgroup_subsys_state *cpu_cgroup_css_alloc(struct cgroup *cgrp)  	return &tg->css;  } +static int cpu_cgroup_css_online(struct cgroup *cgrp) +{ +	struct task_group *tg = cgroup_tg(cgrp); +	struct task_group *parent; + +	if (!cgrp->parent) +		return 0; + +	parent = cgroup_tg(cgrp->parent); +	sched_online_group(tg, parent); +	return 0; +} +  static void cpu_cgroup_css_free(struct cgroup *cgrp)  {  	struct task_group *tg = cgroup_tg(cgrp); @@ -7570,6 +7590,13 @@ static void cpu_cgroup_css_free(struct cgroup *cgrp)  	sched_destroy_group(tg);  } +static void cpu_cgroup_css_offline(struct cgroup *cgrp) +{ +	struct task_group *tg = cgroup_tg(cgrp); + +	sched_offline_group(tg); +} +  static int cpu_cgroup_can_attach(struct cgroup *cgrp,  				 struct cgroup_taskset *tset)  { @@ -7925,6 +7952,8 @@ struct cgroup_subsys cpu_cgroup_subsys = {  	.name		= "cpu",  	.css_alloc	= cpu_cgroup_css_alloc,  	.css_free	= cpu_cgroup_css_free, +	.css_online	= cpu_cgroup_css_online, +	.css_offline	= cpu_cgroup_css_offline,  	.can_attach	= cpu_cgroup_can_attach,  	.attach		= cpu_cgroup_attach,  	.exit		= cpu_cgroup_exit,  |