cgroup: initialize cgrp->dentry before css_alloc()
PATCH v2 1/6 cgroup: initialize cgrp->dentry before css_alloc()
With this change, we're guaranteed that cgroup_path() won't see NULL cgrp->dentry, and thus we can remove the NULL check in it.
(Well, it's not true, because dummptop.dentry is always NULL)
--- kernel/cgroup.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
kernel/cgroup.c +4 -3
@@ -1767,7 +1767,7 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)rcu_lockdep_assert (rcu_read_lock_held () ||cgroup_lock_is_held (),"cgroup_path() called without proper locking" ); -if (!dentry || cgrp == dummytop) { +if (cgrp == dummytop) {/* * Inactive subsystems have no dentry for their root * cgroup
@@ -4153,6 +4153,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,init_cgroup_housekeeping (cgrp); + dentry->d_fsdata = cgrp; + cgrp->dentry = dentry; + cgrp->parent = parent; cgrp->root = parent->root; cgrp->top_cgroup = parent->top_cgroup;
@@ -4190,8 +4193,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,lockdep_assert_held (&dentry->d_inode->i_mutex);/* allocation complete, commit to creation */ - dentry->d_fsdata = cgrp; - cgrp->dentry = dentry;list_add_tail (&cgrp->allcg_node, &root->allcg_list);list_add_tail_rcu (&cgrp->sibling, &cgrp->parent->children); root->number_of_cgroups++;
Signature · 1 line
1.8.0.2
PATCH v2 2/6 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 tgdiput()
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.
---
v2: changelog rephrased
--- include/linux/sched.h | 3 +++ kernel/sched/auto_group.c | 3 +++ kernel/sched/core.c | 49 +++++++++++++++++++++++++++++++++++++---------- 3 files changed, 45 insertions(+), 10 deletions(-)
include/linux/sched.h +3 -0
@@ -2750,7 +2750,10 @@ extern void normalize_rt_tasks(void);extern struct task_group root_task_group;extern struct task_group *sched_create_group (struct task_group *parent); +extern void sched_online_group (struct task_group *tg, +struct task_group *parent);extern void sched_destroy_group (struct task_group *tg); +extern void sched_offline_group (struct task_group *tg);extern void sched_move_task (struct task_struct *tsk);#ifdef CONFIG_FAIR_GROUP_SCHED extern int sched_group_set_shares (struct task_group *tg,unsigned long shares);
kernel/sched/auto_group.c +3 -0
@@ -35,6 +35,7 @@ static inline void autogroup_destroy(struct kref *kref) ag->tg->rt_se =NULL ; ag->tg->rt_rq =NULL ;#endif +sched_offline_group (ag->tg);sched_destroy_group (ag->tg); }
@@ -76,6 +77,8 @@ static inline struct autogroup *autogroup_create(void)if (IS_ERR (tg)) goto out_free; +sched_online_group (tg, &root_task_group); +kref_init (&ag->kref);init_rwsem (&ag->lock); ag->id =atomic_inc_return (&autogroup_seq_nr);
kernel/sched/core.c +39 -10
97 lines not on this page · raw message
Signature · 1 line
1.8.0.2
Re: [PATCH v2 2/6] sched: split out css_online/css_offline from tg creation/destruction
Quoted 28 lines · Li Zefan
This is a preparaton for later patches.
- What do we gain from
cpu_cgroup_css_online():After
ss->css_alloc()and beforess->css_online(), there's a small window thattg->css.cgroupis NULL. With this change, tg won't be seen beforess->css_online(), where it's added to the global list, so we're guaranteed we'll never see NULLtg->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()
noss->css_offline()diput()
syncornize_rcu()
ss->css_free()<-- unregister tg, and free it viacall_rcu()
kfree_rcu(cgroup)<-- wait possible refs to cgroup, and free cgroupWe can't just kfree(cgroup), because tg might access
tg->css.cgroup.With this change:
cgroup_rmdir()
ss->css_offline()<-- unregister tgdiput()
Quoted 7 lines
synchronize_rcu() <-- wait possible refs to tg and cgroup ss->css_free() <-- free tg kfree_rcu(cgroup) <-- free cgroupAs you see,
kfree_rcu()is redundant now.Signed-off-by Li Zefan <[email protected]>
Thanks,
Ingo
Tejun Heo
maintainerRe: [PATCH v2 2/6] sched: split out css_online/css_offline from tg creation/destruction
Quoted 1 line · Ingo Molnar
Acked-by Ingo Molnar <[email protected]>
Ingo, if you don't objecdt, I'll take these through cgroup/for-3.9 branch with other cgroup changes. Pleaes holler if you object.
Thanks.
Signature · 1 line
tejun
Re: [PATCH v2 2/6] sched: split out css_online/css_offline from tg creation/destruction
Quoted 5 lines · Tejun Heo
Quoted 1 line · Ingo Molnar
Acked-by Ingo Molnar <[email protected]>Ingo, if you don't objecdt, I'll take these through cgroup/for-3.9 branch with other cgroup changes. Pleaes holler if you object.
That's fine with me, it should not interact with anything pending in (or planned for) the scheduler tree for this cycle.
Thanks,
Ingo
Re: [PATCH v2 2/6] sched: split out css_online/css_offline from tg creation/destruction
In reply to Li Zefaninclude/linux/sched.h extern void normalize_rt_tasks(void); · line 2756
Quoted 5 lines · Li Zefan
extern struct
task_group*sched_create_group(structtask_group*parent);include/linux/sched.h +3
-0+extern void sched_online_group (struct task_group *tg, +struct task_group *parent);extern void sched_destroy_group (struct task_group *tg); +extern void sched_offline_group (struct task_group *tg);
Btw., a rename of these APIs might be in order, along the usual patterns:
sched_task_group_create()
sched_task_group_online()
sched_task_group_offline()
sched_task_group_destroy()
etc.
that way the naming is more hierarchical and there's no clash with the sched_group concept which is about something else.
(In a separate patch.)
Thanks,
Ingo
Re: [PATCH v2 2/6] sched: split out css_online/css_offline from tg creation/destruction
Quoted 17 lines · Ingo Molnar
include/linux/sched.h extern void normalize_rt_tasks(void); · line 2756
Quoted 5 lines · Li Zefan
extern struct
task_group*sched_create_group(structtask_group*parent);include/linux/sched.h +3
-0+extern void sched_online_group (struct task_group *tg, +struct task_group *parent);extern void sched_destroy_group (struct task_group *tg); +extern void sched_offline_group (struct task_group *tg);Btw., a rename of these APIs might be in order, along the usual patterns:
sched_task_group_create()
sched_task_group_online()
sched_task_group_offline()
sched_task_group_destroy()
Quoted 7 lines
etc.
that way the naming is more hierarchical and there's no clash with the
sched_groupconcept which is about something else.(In a separate patch.)
Agreed. I'll send a cleanup patch to you when those patches hit mainline. (That will be 3.9-rc1 or later)
PATCH v2 3/6 sched: remove redundant NULL cgroup check in task_group_path()
In reply to Li ZefanA task_group won't be online (thus no one can see it) until cpu_cgroup_css_online(), and at that time tg->css.cgroup has been initialized, so this NULL check is redundant.
--- kernel/sched/debug.c | 7 ------- 1 file changed, 7 deletions(-)
kernel/sched/debug.c +0 -7
@@ -110,13 +110,6 @@ static char *task_group_path(struct task_group *tg)if (autogroup_path (tg, group_path,PATH_MAX ))return group_path; -/* -* May be NULL if the underlying cgroup isn't fully-created yet -*/ -if (!tg->css.cgroup) { - group_path[0 ] ='\0' ; -return group_path; - }cgroup_path (tg->css.cgroup, group_path,PATH_MAX );return group_path; }
Signature · 1 line
1.8.0.2
PATCH v2 4/6 cgroup: remove duplicate RCU free on struct cgroup
In reply to Li ZefanWhen destroying a cgroup, though in cgroup_diput() we've called synchronize_rcu(), we then still have to free it via call_rcu().
The story is, long ago to fix a race between reading /proc/sched_debug and freeing cgroup, the code was changed to utilize call_rcu(). See commit a47295e6bc42ad35f9c15ac66f598aa24debd4e2 ("cgroups: make cgroup_path() RCU-safe")
As we've fixed cpu cgroup that cpu_cgroup_offline_css() is used to unregister a task_group so there won't be concurrent access to this task_group after synchronize_rcu() in diput(). Now we can just kfree(cgrp).
--- kernel/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cgroup.c +1 -1
@@ -892,7 +892,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)simple_xattrs_free (&cgrp->xattrs);ida_simple_remove (&cgrp->root->cgroup_ida, cgrp->id); -kfree_rcu (cgrp, rcu_head); +kfree (cgrp); }else {struct cfent *cfe =__d_cfe (dentry);struct cgroup *cgrp = dentry->d_parent->d_fsdata;
Signature · 1 line
1.8.0.2
PATCH v2 5/6 cgroup: remove synchronize_rcu() from cgroup_diput()
In reply to Li ZefanFree cgroup via call_rcu(). The actual work is done through workqueue.
---
v2: move INIT_WORK() from cgroup_create() to init_cgroup_housekeeping()
--- include/linux/cgroup.h | 1 + kernel/cgroup.c | 72 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 29 deletions(-)
include/linux/cgroup.h +1 -0
@@ -203,6 +203,7 @@ struct cgroup {/* For RCU-protected deletion */ struct rcu_head rcu_head; +struct work_struct free_work;/* List of events which userspace want to receive */ struct list_head event_list;
kernel/cgroup.c +43 -29
95 lines not on this page · raw message
Signature · 1 line
1.8.0.2
PATCH v2 6/6 cgroup: remove bogus comments in cgroup_diput()
In reply to Li ZefanSince commit 48ddbe194623ae089cc0576e60363f2d2e85662a ("cgroup: make css->refcnt clearing on cgroup removal optional"), each css holds a ref on cgroup's dentry, so cgroup_diput() won't be called until all css' refs go down to 0, which invalids the comments.
--- kernel/cgroup.c | 6 ------ 1 file changed, 6 deletions(-)
kernel/cgroup.c +0 -6
@@ -899,12 +899,6 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)struct cgroup *cgrp = dentry->d_fsdata;BUG_ON (!(cgroup_is_removed (cgrp))); -/* It's possible for external users to be holding css -* reference counts on a cgroup; css_put() needs to -* be able to access the cgroup after decrementing -* the reference count in order to know if it needs to -* queue the cgroup to be handled by the release -* agent */ call_rcu (&cgrp->rcu_head, cgroup_free_rcu); }else {struct cfent *cfe =__d_cfe (dentry);
Signature · 1 line
1.8.0.2
Tejun Heo
maintainerRe: [PATCH v2 6/6] cgroup: remove bogus comments in cgroup_diput()
Hello, Li.
Quoted 15 lines · Li Zefan
Since commit
48ddbe194623ae089cc0576e60363f2d2e85662a("cgroup: makecss->refcntclearing on cgroup removal optional"), each css holds a ref on cgroup's dentry, socgroup_diput()won't be called until all css' refs go down to 0, which invalids the comments.Signed-off-by Li Zefan <[email protected]>--- kernel/cgroup.c | 6 ------ 1 file changed, 6 deletions(-)kernel/cgroup.c +0
-0
kernel/cgroup.c static void cgroup_diput(struct dentry *dentry, struct inode *inode) · line 907
Quoted 9 lines
kernel/cgroup.c +0
-6@@ -899,12 +899,6 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)struct cgroup *cgrp = dentry->d_fsdata;BUG_ON (!(cgroup_is_removed (cgrp))); -/* It's possible for external users to be holding css -* reference counts on a cgroup; css_put() needs to -* be able to access the cgroup after decrementing -* the reference count in order to know if it needs to -* queue the cgroup to be handled by the release -* agent */
The latter half is still true tho. I applied the patch anyway as the comment isn't all that useful without covering everything intended to be covered with RCU. Can you please write up another patch documenting what's covered by RCU (stuff that we intend to keep guaranteeing to be safe to access only w/ RCU)?
Thanks.
Signature · 1 line
tejun
Re: [PATCH v2 6/6] cgroup: remove bogus comments in cgroup_diput()
Quoted 18 lines · Li Zefan
Quoted 17 lines
Since commit
48ddbe194623ae089cc0576e60363f2d2e85662a("cgroup: makecss->refcntclearing on cgroup removal optional"), each css holds a ref on cgroup's dentry, socgroup_diput()won't be called until all css' refs go down to 0, which invalids the comments.Signed-off-by Li Zefan <[email protected]>--- kernel/cgroup.c | 6 ------ 1 file changed, 6 deletions(-)kernel/cgroup.c +0
-0@@ -899,12 +899,6 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)struct cgroup *cgrp = dentry->d_fsdata;
Quoted 14 lines
kernel/cgroup.c static void cgroup_diput(struct dentry *dentry, struct inode *inode) · line 907
Quoted 7 lines
kernel/cgroup.c +0
-6BUG_ON (!(cgroup_is_removed (cgrp))); -/* It's possible for external users to be holding css -* reference counts on a cgroup; css_put() needs to -* be able to access the cgroup after decrementing -* the reference count in order to know if it needs to -* queue the cgroup to be handled by the release -* agent */ The latter half is still true tho. I applied the patch anyway as the comment isn't all that useful without covering everything intended to be covered with RCU. Can you please write up another patch documenting what's covered by RCU (stuff that we intend to keep guaranteeing to be safe to access only w/ RCU)?
Sure. I'll try.
Tejun Heo
maintainerQuoted 6 lines · Li Zefan
With this change, we're guaranteed that
cgroup_path()won't see NULLcgrp->dentry, and thus we can remove the NULL check in it.(Well, it's not true, because dummptop.dentry is always NULL)
Signed-off-by Li Zefan <[email protected]>
Appled 1-6 to cgroup/for-3.9.
Thanks.
Signature · 1 line
tejun