cgroup: factor out css creation into create_css()
Tejun Heo
maintainerPATCH 1/1 cgroup: factor out css creation into create_css()
Hello,
For unified hierarchy, a css's (cgroup_subsys_state) lifetime will be different from that of the associated cgroup. css's may be created and destroyed dynamically over the lifetime of a single cgroup. The previous changes decoupled css destruction from cgroup's. This patchset decouples css creation from cgroup's.
This patchset contains the following nine patches.
0001-cgroup-fix-css-leaks-on-online_css-failure.patch 0002-cgroup-css-iterations-and-css_from_dir-are-safe-unde.patch 0003-cgroup-make-for_each_subsys-useable-under-cgroup_roo.patch 0004-cgroup-move-css_id-commit-from-cgroup_populate_dir-t.patch 0005-cgroup-reorder-operations-in-cgroup_create.patch 0006-cgroup-combine-css-handling-loops-in-cgroup_create.patch 0007-cgroup-factor-out-cgroup_subsys_state-creation-into-.patch 0008-cgroup-implement-for_each_css.patch 0009-cgroup-remove-for_each_root_subsys.patch
0001 is a fix for an existing leak issue in the creation error handling path.
0002-0004 are prep patches. Note that 0004 will conflict with css_id removal patch.
0005-0007 collect css creation operations into single loop and factor it out into create_css().
0008-0009 are somewhat tangential. As everything is css based now and the enabled set of css's might be differ depending on the specific cgroup in the future, they introduce for_each_css() and replace most uses of for_each_root_subsys() with it. The two left overs are opencoded and for_each_root_subsys() and the related logic are removed.
This patchset shouldn't bring any userland noticeable behavior changes. It's on top of cgroup/for-3.12 d1625964da ("cgroup: fix cgroup_css() invocation in css_from_id()") and available in the following git branch.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git review-create_css
diffstat follows.
include/linux/cgroup.h | 10 - kernel/cgroup.c | 348 ++++++++++++++++++++++++++----------------------- 2 files changed, 187 insertions(+), 171 deletions(-)
Thanks.
--
tejun
Tejun Heo
maintainerPATCH 1/9 cgroup: fix css leaks on online_css() failure
ae7f164a09 ("cgroup: move cgroup->subsys[] assignment to online_css()") moved cgroup->subsys[] assignements later in cgroup_create() but didn't update error handling path accordingly leaking later css's after an online_css() failure.
This patch moves reference bumping inside online_css() loop, clears css_ar[] as css's are brought online successfully, and updates err_destroy path so that either a css is fully online and destroyed by cgroup_destroy_locked() or the error path frees it. This creates a duplicate css free logic in the error path but it will be cleaned up soon.
--- kernel/cgroup.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
kernel/cgroup.c +15 -8
@@ -4489,14 +4489,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,list_add_tail_rcu (&cgrp->sibling, &cgrp->parent->children); root->number_of_cgroups++; -/* each css holds a ref to the cgroup's dentry and the parent css */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; - -dget (dentry); -css_get (css->parent); - } -/* hold a ref to the parent's dentry */ dget (parent->dentry);
@@ -4508,6 +4500,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,if (err) goto err_destroy; +/* each css holds a ref to the cgroup's dentry and parent css */ +dget (dentry); +css_get (css->parent); + +/* mark it consumed for error path */ + css_ar[ss->subsys_id] =NULL ; +if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && parent->parent) { pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n",
@@ -4554,6 +4553,14 @@ err_free_cgrp:return err; err_destroy: +for_each_root_subsys (root, ss) { +struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; + +if (css) { +percpu_ref_cancel_init (&css->refcnt); + ss->css_free (css); + } + }cgroup_destroy_locked (cgrp);mutex_unlock (&cgroup_mutex);mutex_unlock (&dentry->d_inode->i_mutex);
Signature · 1 line
1.8.3.1
Re: [PATCH 1/9] cgroup: fix css leaks on online_css() failure
Quoted 37 lines · Tejun Heo
ae7f164a09("cgroup: move cgroup->subsys[] assignment toonline_css()") moved cgroup->subsys[] assignements later incgroup_create()but didn't update error handling path accordingly leaking later css's after anonline_css()failure.This patch moves reference bumping inside
online_css()loop, clears css_ar[] as css's are brought online successfully, and updateserr_destroypath so that either a css is fully online and destroyed bycgroup_destroy_locked()or the error path frees it. This creates a duplicate css free logic in the error path but it will be cleaned up soon.Signed-off-by Tejun Heo <[email protected]>--- kernel/cgroup.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)kernel/cgroup.c +0
-8@@ -4489,14 +4489,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,list_add_tail_rcu (&cgrp->sibling, &cgrp->parent->children); root->number_of_cgroups++; -/* each css holds a ref to the cgroup's dentry and the parent css */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; - -dget (dentry); -css_get (css->parent); - } -/* hold a ref to the parent's dentry */ dget (parent->dentry);
kernel/cgroup.c static long cgroup_create(struct cgroup *parent, struct dentry *dentry, · line 4501
Quoted 2 lines
kernel/cgroup.c +0
-0@@ -4508,6 +4500,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,if (err) goto err_destroy;
If online_css() returns -error, it means cgroup->subsys[ss->subsys_id] == NULL,
Quoted 14 lines
kernel/cgroup.c +7
-0+/* each css holds a ref to the cgroup's dentry and parent css */ +dget (dentry); +css_get (css->parent); + +/* mark it consumed for error path */ + css_ar[ss->subsys_id] =NULL ; +if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && parent->parent) { pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n",@@ -4554,6 +4553,14 @@ err_free_cgrp:return err;
kernel/cgroup.c err_free_cgrp: · line 4564
Quoted 10 lines
kernel/cgroup.c +8
-0err_destroy: +for_each_root_subsys (root, ss) { +struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; + +if (css) { +percpu_ref_cancel_init (&css->refcnt); + ss->css_free (css); + } + }cgroup_destroy_locked (cgrp);
Now cgroup_destroy_locked() is called:
for_each_root_subsys(cgrp->root, ss) kill_css(cgroup_css(cgrp, ss));
cgroup_css(cgrp, ss) will return NULL and pass it to kill_css(), which leads to NULL pointer deref ?
kernel/cgroup.c err_free_cgrp: · line 4566
Quoted 3 lines
kernel/cgroup.c +0
-0mutex_unlock (&cgroup_mutex);mutex_unlock (&dentry->d_inode->i_mutex);
(I'll go through the patchset tomorrow.)
Tejun Heo
maintainerRe: [PATCH 1/9] cgroup: fix css leaks on online_css() failure
Hello,
Quoted 4 lines · Li Zefan
Now
cgroup_destroy_locked()is called:for_each_root_subsys(cgrp->root, ss) kill_css(cgroup_css(cgrp, ss));
Oops, yes, later in the series, for_each_css() is introduced and replaces for_each_root_subsys() usages solving the above problem. I should have put those patches before this one. Will re-sequence the patches.
Thanks.
Signature · 1 line
tejun
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH 1/9] cgroup: fix css leaks on online_css() failure
Hello,
Quoted 4 lines · Li Zefan
Now
cgroup_destroy_locked()is called:for_each_root_subsys(cgrp->root, ss) kill_css(cgroup_css(cgrp, ss));
Oops, yes, later in the series, for_each_css() is introduced and replaces for_each_root_subsys() usages solving the above problem. I should have put those patches before this one. Will re-sequence the patches.
Thanks.
Signature · 1 line
tejun
Tejun Heo
maintainerPATCH v2 1/9 cgroup: fix css leaks on online_css() failure
In reply to Tejun HeoOkay, re-sequencing the for_each_css patch turns out to be a lot more headache than expected. Let's just fix it up in this patch proper. It's a standalone bug fix anyway. The change only affects the for_each_css() patch later. Will post an updated version of that patch too soon.
Thanks.
----- 8< -----ae7f164a09 ("cgroup: move cgroup->subsys[] assignment to online_css()") moved cgroup->subsys[] assignements later in cgroup_create() but didn't update error handling path accordingly leaking later css's after an online_css() failure.
This patch moves reference bumping inside online_css() loop, clears css_ar[] as css's are brought online successfully, and updates err_destroy path so that either a css is fully online and destroyed by cgroup_destroy_locked() or the error path frees it. This creates a duplicate css free logic in the error path but it will be cleaned up soon.
v2: Li pointed out that cgroup_destroy_locked() would do NULL-deref if
invoked with a cgroup which doesn't have all css's populated. Update cgroup_destroy_locked() so that it skips NULL css's.
--- kernel/cgroup.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-)
kernel/cgroup.c +21 -10
@@ -4489,14 +4489,6 @@ static long cgroup_create(struct cgrouplist_add_tail_rcu (&cgrp->sibling, &cgrp->parent->children); root->number_of_cgroups++; -/* each css holds a ref to the cgroup's dentry and the parent css */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; - -dget (dentry); -css_get (css->parent); - } -/* hold a ref to the parent's dentry */ dget (parent->dentry);
@@ -4508,6 +4500,13 @@ static long cgroup_create(struct cgroupif (err) goto err_destroy; +/* each css holds a ref to the cgroup's dentry and parent css */ +dget (dentry); +css_get (css->parent); + +/* mark it consumed for error path */ + css_ar[ss->subsys_id] =NULL ; +if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && parent->parent) { pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n",
@@ -4554,6 +4553,14 @@ err_free_cgrp:return err; err_destroy: +for_each_root_subsys (root, ss) { +struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; + +if (css) { +percpu_ref_cancel_init (&css->refcnt); + ss->css_free (css); + } + }cgroup_destroy_locked (cgrp);mutex_unlock (&cgroup_mutex);mutex_unlock (&dentry->d_inode->i_mutex);
@@ -4698,8 +4705,12 @@ static int cgroup_destroy_locked(struct* will be invoked to perform the rest of destruction once the * percpu refs of all css's are confirmed to be killed. */ -for_each_root_subsys (cgrp->root, ss) -kill_css (cgroup_css (cgrp, ss)); +for_each_root_subsys (cgrp->root, ss) { +struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); + +if (css) +kill_css (css); + }/* * Mark @cgrp dead. This prevents further task migration and child
Tejun Heo
maintainerPATCH 2/9 cgroup: css iterations and css_from_dir() are safe under cgroup_mutex
In reply to Tejun HeoCurrently, all css iterations and css_from_dir() require RCU read lock whether the caller is holding cgroup_mutex or not, which is unnecessarily restrictive. They are all safe to use under cgroup_mutex without holding RCU read lock.
Factor out cgroup_assert_mutex_or_rcu_locked() from css_from_id() and apply it to all css iteration functions and css_from_dir().
--- kernel/cgroup.c | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-)
kernel/cgroup.c +30 -26
@@ -82,8 +82,13 @@#ifdef CONFIG_PROVE_RCU DEFINE_MUTEX (cgroup_mutex);EXPORT_SYMBOL_GPL (cgroup_mutex);/* only for lockdep */ +#define cgroup_assert_mutex_or_rcu_locked () \ + rcu_lockdep_assert(rcu_read_lock_held() || \ + lockdep_is_held(&cgroup_mutex), \ + "cgroup_mutex or RCU read lock required");#else static DEFINE_MUTEX (cgroup_mutex); +#define cgroup_assert_mutex_or_rcu_locked () do { } while (false)#endif static DEFINE_MUTEX (cgroup_root_mutex);
@@ -3036,9 +3041,9 @@ static void cgroup_enable_task_cg_lists(void)* @parent_css: css whose children to walk * * This function returns the next child of @parent_css and should be called -* under RCU read lock. The only requirement is that @parent_css and -* @pos_css are accessible. The next sibling is guaranteed to be returned -* regardless of their states. +* under either cgroup_mutex or RCU read lock. The only requirement is +* that @parent_css and @pos_css are accessible. The next sibling is +* guaranteed to be returned regardless of their states. */ struct cgroup_subsys_state * css_next_child(struct cgroup_subsys_state *pos_css,
@@ -3048,7 +3053,7 @@ css_next_child(struct cgroup_subsys_state *pos_css,struct cgroup *cgrp = parent_css->cgroup;struct cgroup *next; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* * @pos could already have been removed. Once a cgroup is removed,
@@ -3095,10 +3100,10 @@ EXPORT_SYMBOL_GPL(css_next_child);* to visit for pre-order traversal of @root's descendants. @root is * included in the iteration and the first node to be visited. * -* While this function requires RCU read locking, it doesn't require the -* whole traversal to be contained in a single RCU critical section. This -* function will return the correct next descendant as long as both @pos -* and @root are accessible and @pos is a descendant of @root. +* While this function requires cgroup_mutex or RCU read locking, it +* doesn't require the whole traversal to be contained in a single critical +* section. This function will return the correct next descendant as long +* as both @pos and @root are accessible and @pos is a descendant of @root. */ struct cgroup_subsys_state * css_next_descendant_pre(struct cgroup_subsys_state *pos,
@@ -3106,7 +3111,7 @@ css_next_descendant_pre(struct cgroup_subsys_state *pos, {struct cgroup_subsys_state *next; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* if first iteration, visit @root */ if (!pos)
@@ -3137,17 +3142,17 @@ EXPORT_SYMBOL_GPL(css_next_descendant_pre);* is returned. This can be used during pre-order traversal to skip * subtree of @pos. * -* While this function requires RCU read locking, it doesn't require the -* whole traversal to be contained in a single RCU critical section. This -* function will return the correct rightmost descendant as long as @pos is -* accessible. +* While this function requires cgroup_mutex or RCU read locking, it +* doesn't require the whole traversal to be contained in a single critical +* section. This function will return the correct rightmost descendant as +* long as @pos is accessible. */ struct cgroup_subsys_state *css_rightmost_descendant (struct cgroup_subsys_state *pos) {struct cgroup_subsys_state *last, *tmp; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked (); do { last = pos;
@@ -3183,10 +3188,11 @@ css_leftmost_descendant(struct cgroup_subsys_state *pos)* to visit for post-order traversal of @root's descendants. @root is * included in the iteration and the last node to be visited. * -* While this function requires RCU read locking, it doesn't require the -* whole traversal to be contained in a single RCU critical section. This -* function will return the correct next descendant as long as both @pos -* and @cgroup are accessible and @pos is a descendant of @cgroup. +* While this function requires cgroup_mutex or RCU read locking, it +* doesn't require the whole traversal to be contained in a single critical +* section. This function will return the correct next descendant as long +* as both @pos and @cgroup are accessible and @pos is a descendant of +* @cgroup. */ struct cgroup_subsys_state * css_next_descendant_post(struct cgroup_subsys_state *pos,
@@ -3194,7 +3200,7 @@ css_next_descendant_post(struct cgroup_subsys_state *pos, {struct cgroup_subsys_state *next; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* if first iteration, visit the leftmost descendant */ if (!pos) {
@@ -5698,16 +5704,16 @@ EXPORT_SYMBOL_GPL(css_lookup);* @dentry: directory dentry of interest * @ss: subsystem of interest * -* Must be called under RCU read lock. The caller is responsible for -* pinning the returned css if it needs to be accessed outside the RCU -* critical section. +* Must be called under cgroup_mutex or RCU read lock. The caller is +* responsible for pinning the returned css if it needs to be accessed +* outside the critical section. */ struct cgroup_subsys_state *css_from_dir (struct dentry *dentry,struct cgroup_subsys *ss) {struct cgroup *cgrp; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* is @dentry a cgroup dir? */ if (!dentry->d_inode ||
@@ -5730,9 +5736,7 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss) {struct cgroup *cgrp; -rcu_lockdep_assert (rcu_read_lock_held () || -lockdep_is_held (&cgroup_mutex), -"css_from_id() needs proper protection" ); +cgroup_assert_mutex_or_rcu_locked (); cgrp =idr_find (&ss->root->cgroup_idr, id);if (cgrp)
Signature · 1 line
1.8.3.1
Tejun Heo
maintainerPATCH v2 2/9 cgroup: css iterations and css_from_dir() are safe under cgroup_mutex
Currently, all css iterations and css_from_dir() require RCU read lock whether the caller is holding cgroup_mutex or not, which is unnecessarily restrictive. They are all safe to use under cgroup_mutex without holding RCU read lock.
Factor out cgroup_assert_mutex_or_rcu_locked() from css_from_id() and apply it to all css iteration functions and css_from_dir().
v2: cgroup_assert_mutex_or_rcu_locked() definition doesn't need to be
inside CONFIG_PROVE_RCU ifdef as rcu_lockdep_assert() is always defined and conditionalized. Move it outside of the ifdef block.
--- kernel/cgroup.c | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-)
kernel/cgroup.c +30 -26
@@ -88,6 +88,11 @@ static DEFINE_MUTEX(cgroup_mutex);static DEFINE_MUTEX (cgroup_root_mutex); +#define cgroup_assert_mutex_or_rcu_locked () \ + rcu_lockdep_assert(rcu_read_lock_held() || \ + lockdep_is_held(&cgroup_mutex), \ + "cgroup_mutex or RCU read lock required"); +/* * Generate an array of cgroup subsystem pointers. At boot time, this is * populated with the built in subsystems, and modular subsystems are
@@ -3036,9 +3041,9 @@ static void cgroup_enable_task_cg_lists(* @parent_css: css whose children to walk * * This function returns the next child of @parent_css and should be called -* under RCU read lock. The only requirement is that @parent_css and -* @pos_css are accessible. The next sibling is guaranteed to be returned -* regardless of their states. +* under either cgroup_mutex or RCU read lock. The only requirement is +* that @parent_css and @pos_css are accessible. The next sibling is +* guaranteed to be returned regardless of their states. */ struct cgroup_subsys_state * css_next_child(struct cgroup_subsys_state *pos_css,
@@ -3048,7 +3053,7 @@ css_next_child(struct cgroup_subsys_statstruct cgroup *cgrp = parent_css->cgroup;struct cgroup *next; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* * @pos could already have been removed. Once a cgroup is removed,
@@ -3095,10 +3100,10 @@ EXPORT_SYMBOL_GPL(css_next_child);* to visit for pre-order traversal of @root's descendants. @root is * included in the iteration and the first node to be visited. * -* While this function requires RCU read locking, it doesn't require the -* whole traversal to be contained in a single RCU critical section. This -* function will return the correct next descendant as long as both @pos -* and @root are accessible and @pos is a descendant of @root. +* While this function requires cgroup_mutex or RCU read locking, it +* doesn't require the whole traversal to be contained in a single critical +* section. This function will return the correct next descendant as long +* as both @pos and @root are accessible and @pos is a descendant of @root. */ struct cgroup_subsys_state * css_next_descendant_pre(struct cgroup_subsys_state *pos,
@@ -3106,7 +3111,7 @@ css_next_descendant_pre(struct cgroup_su {struct cgroup_subsys_state *next; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* if first iteration, visit @root */ if (!pos)
@@ -3137,17 +3142,17 @@ EXPORT_SYMBOL_GPL(css_next_descendant_pr* is returned. This can be used during pre-order traversal to skip * subtree of @pos. * -* While this function requires RCU read locking, it doesn't require the -* whole traversal to be contained in a single RCU critical section. This -* function will return the correct rightmost descendant as long as @pos is -* accessible. +* While this function requires cgroup_mutex or RCU read locking, it +* doesn't require the whole traversal to be contained in a single critical +* section. This function will return the correct rightmost descendant as +* long as @pos is accessible. */ struct cgroup_subsys_state *css_rightmost_descendant (struct cgroup_subsys_state *pos) {struct cgroup_subsys_state *last, *tmp; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked (); do { last = pos;
@@ -3183,10 +3188,11 @@ css_leftmost_descendant(struct cgroup_su* to visit for post-order traversal of @root's descendants. @root is * included in the iteration and the last node to be visited. * -* While this function requires RCU read locking, it doesn't require the -* whole traversal to be contained in a single RCU critical section. This -* function will return the correct next descendant as long as both @pos -* and @cgroup are accessible and @pos is a descendant of @cgroup. +* While this function requires cgroup_mutex or RCU read locking, it +* doesn't require the whole traversal to be contained in a single critical +* section. This function will return the correct next descendant as long +* as both @pos and @cgroup are accessible and @pos is a descendant of +* @cgroup. */ struct cgroup_subsys_state * css_next_descendant_post(struct cgroup_subsys_state *pos,
@@ -3194,7 +3200,7 @@ css_next_descendant_post(struct cgroup_s {struct cgroup_subsys_state *next; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* if first iteration, visit the leftmost descendant */ if (!pos) {
@@ -5698,16 +5704,16 @@ EXPORT_SYMBOL_GPL(css_lookup);* @dentry: directory dentry of interest * @ss: subsystem of interest * -* Must be called under RCU read lock. The caller is responsible for -* pinning the returned css if it needs to be accessed outside the RCU -* critical section. +* Must be called under cgroup_mutex or RCU read lock. The caller is +* responsible for pinning the returned css if it needs to be accessed +* outside the critical section. */ struct cgroup_subsys_state *css_from_dir (struct dentry *dentry,struct cgroup_subsys *ss) {struct cgroup *cgrp; -WARN_ON_ONCE (!rcu_read_lock_held ()); +cgroup_assert_mutex_or_rcu_locked ();/* is @dentry a cgroup dir? */ if (!dentry->d_inode ||
@@ -5730,9 +5736,7 @@ struct cgroup_subsys_state *css_from_id( {struct cgroup *cgrp; -rcu_lockdep_assert (rcu_read_lock_held () || -lockdep_is_held (&cgroup_mutex), -"css_from_id() needs proper protection" ); +cgroup_assert_mutex_or_rcu_locked (); cgrp =idr_find (&ss->root->cgroup_idr, id);if (cgrp)
Tejun Heo
maintainerPATCH 3/9 cgroup: make for_each_subsys() useable under cgroup_root_mutex
In reply to Tejun HeoWe want to use for_each_subsys() in cgroupfs_root handling where only cgroup_root_mutex is held. The only way cgroup_subsys[] can change is through module load/unload, make cgroup_[un]load_subsys() grab cgroup_root_mutex too and update the lockdep annotation in for_each_subsys() to allow either cgroup_mutex or cgroup_root_mutex.
* Lockdep annotation is moved from inner 'if' condition to outer 'for' init caluse. There's no reason to execute the assertion every loop.
* Loop index @i is renamed to @ssid. Indices iterating through subsys will be [re]named to @ssid gradually.
--- kernel/cgroup.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
kernel/cgroup.c +14 -6
@@ -291,14 +291,17 @@ static int notify_on_release(const struct cgroup *cgrp)/** * for_each_subsys - iterate all loaded cgroup subsystems * @ss: the iteration cursor -* @i: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end +* @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end * -* Should be called under cgroup_mutex. +* Iterates through all loaded subsystems. Should be called under +* cgroup_mutex or cgroup_root_mutex. */ -#define for_each_subsys (ss, i) \ - for ((i) = 0; (i) < CGROUP_SUBSYS_COUNT; (i)++) \ - if (({ lockdep_assert_held(&cgroup_mutex); \ - !((ss) = cgroup_subsys[i]); })) { } \ +#define for_each_subsys (ss, ssid) \ + for (({ WARN_ON_ONCE(debug_locks && \ + (!lockdep_is_held(&cgroup_mutex) && \ + !lockdep_is_held(&cgroup_root_mutex))); \ + (ssid) = 0; }); (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ + if (!((ss) = cgroup_subsys[(ssid)])) { } \ else/**
@@ -4911,6 +4914,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)cgroup_init_cftsets (ss);mutex_lock (&cgroup_mutex); +mutex_lock (&cgroup_root_mutex); cgroup_subsys[ss->subsys_id] = ss;/*
@@ -4966,10 +4970,12 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) goto err_unload;/* success! */ +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex);return 0 ; err_unload: +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex);/* @ss can't be mounted here as try_module_get() would fail */ cgroup_unload_subsys (ss);
@@ -4999,6 +5005,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)BUG_ON (ss->root != &cgroup_dummy_root);mutex_lock (&cgroup_mutex); +mutex_lock (&cgroup_root_mutex);offline_css (cgroup_css (cgroup_dummy_top, ss));
@@ -5037,6 +5044,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) ss->css_free (cgroup_css (cgroup_dummy_top, ss));RCU_INIT_POINTER (cgroup_dummy_top->subsys[ss->subsys_id],NULL ); +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex); }EXPORT_SYMBOL_GPL (cgroup_unload_subsys);
Signature · 1 line
1.8.3.1
Tejun Heo
maintainerPATCH v2 3/9 cgroup: make for_each_subsys() useable under cgroup_root_mutex
We want to use for_each_subsys() in cgroupfs_root handling where only cgroup_root_mutex is held. The only way cgroup_subsys[] can change is through module load/unload, make cgroup_[un]load_subsys() grab cgroup_root_mutex too and update the lockdep annotation in for_each_subsys() to allow either cgroup_mutex or cgroup_root_mutex.
* Lockdep annotation is moved from inner 'if' condition to outer 'for' init caluse. There's no reason to execute the assertion every loop.
* Loop index @i is renamed to @ssid. Indices iterating through subsys will be [re]named to @ssid gradually.
v2: cgroup_assert_mutex_or_root_locked() caused build failure if
!CONFIG_LOCKEDP. Conditionalize its definition. The build failure was reported by kbuild test bot.
--- kernel/cgroup.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
kernel/cgroup.c +20 -6
@@ -93,6 +93,14 @@ static DEFINE_MUTEX(cgroup_root_mutex);lockdep_is_held (&cgroup_mutex), \ "cgroup_mutex or RCU read lock required"); +#ifdef CONFIG_LOCKDEP +#define cgroup_assert_mutex_or_root_locked () \ + WARN_ON_ONCE(debug_locks && (!lockdep_is_held(&cgroup_mutex) && \ + !lockdep_is_held(&cgroup_root_mutex))) +#else +#define cgroup_assert_mutex_or_root_locked () do { } while (0) +#endif +/* * Generate an array of cgroup subsystem pointers. At boot time, this is * populated with the built in subsystems, and modular subsystems are
@@ -291,14 +299,15 @@ static int notify_on_release(const struc/** * for_each_subsys - iterate all loaded cgroup subsystems * @ss: the iteration cursor -* @i: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end +* @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end * -* Should be called under cgroup_mutex. +* Iterates through all loaded subsystems. Should be called under +* cgroup_mutex or cgroup_root_mutex. */ -#define for_each_subsys (ss, i) \ - for ((i) = 0; (i) < CGROUP_SUBSYS_COUNT; (i)++) \ - if (({ lockdep_assert_held(&cgroup_mutex); \ - !((ss) = cgroup_subsys[i]); })) { } \ +#define for_each_subsys (ss, ssid) \ + for (({ cgroup_assert_mutex_or_root_locked(); (ssid) = 0; }); \ + (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ + if (!((ss) = cgroup_subsys[(ssid)])) { } \ else/**
@@ -4911,6 +4920,7 @@ int __init_or_module cgroup_load_subsys(cgroup_init_cftsets (ss);mutex_lock (&cgroup_mutex); +mutex_lock (&cgroup_root_mutex); cgroup_subsys[ss->subsys_id] = ss;/*
@@ -4966,10 +4976,12 @@ int __init_or_module cgroup_load_subsys( goto err_unload;/* success! */ +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex);return 0 ; err_unload: +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex);/* @ss can't be mounted here as try_module_get() would fail */ cgroup_unload_subsys (ss);
@@ -4999,6 +5011,7 @@ void cgroup_unload_subsys(struct cgroup_BUG_ON (ss->root != &cgroup_dummy_root);mutex_lock (&cgroup_mutex); +mutex_lock (&cgroup_root_mutex);offline_css (cgroup_css (cgroup_dummy_top, ss));
@@ -5037,6 +5050,7 @@ void cgroup_unload_subsys(struct cgroup_ ss->css_free (cgroup_css (cgroup_dummy_top, ss));RCU_INIT_POINTER (cgroup_dummy_top->subsys[ss->subsys_id],NULL ); +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex); }EXPORT_SYMBOL_GPL (cgroup_unload_subsys);
A message that is not in the archive (sent off-list or not yet received): 1377723829-22814-4-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
PATCH v2 3/9 cgroup: make for_each_subsys() useable under cgroup_root_mutex
We want to use for_each_subsys() in cgroupfs_root handling where only cgroup_root_mutex is held. The only way cgroup_subsys[] can change is through module load/unload, make cgroup_[un]load_subsys() grab cgroup_root_mutex too and update the lockdep annotation in for_each_subsys() to allow either cgroup_mutex or cgroup_root_mutex.
* Lockdep annotation is moved from inner 'if' condition to outer 'for' init caluse. There's no reason to execute the assertion every loop.
* Loop index @i is renamed to @ssid. Indices iterating through subsys will be [re]named to @ssid gradually.
v2: cgroup_assert_mutex_or_root_locked() caused build failure if
!CONFIG_LOCKEDP. Conditionalize its definition. The build failure was reported by kbuild test bot.
--- kernel/cgroup.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
kernel/cgroup.c +20 -6
@@ -93,6 +93,14 @@ static DEFINE_MUTEX(cgroup_root_mutex);lockdep_is_held (&cgroup_mutex), \ "cgroup_mutex or RCU read lock required"); +#ifdef CONFIG_LOCKDEP +#define cgroup_assert_mutex_or_root_locked () \ + WARN_ON_ONCE(debug_locks && (!lockdep_is_held(&cgroup_mutex) && \ + !lockdep_is_held(&cgroup_root_mutex))) +#else +#define cgroup_assert_mutex_or_root_locked () do { } while (0) +#endif +/* * Generate an array of cgroup subsystem pointers. At boot time, this is * populated with the built in subsystems, and modular subsystems are
@@ -291,14 +299,15 @@ static int notify_on_release(const struc/** * for_each_subsys - iterate all loaded cgroup subsystems * @ss: the iteration cursor -* @i: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end +* @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end * -* Should be called under cgroup_mutex. +* Iterates through all loaded subsystems. Should be called under +* cgroup_mutex or cgroup_root_mutex. */ -#define for_each_subsys (ss, i) \ - for ((i) = 0; (i) < CGROUP_SUBSYS_COUNT; (i)++) \ - if (({ lockdep_assert_held(&cgroup_mutex); \ - !((ss) = cgroup_subsys[i]); })) { } \ +#define for_each_subsys (ss, ssid) \ + for (({ cgroup_assert_mutex_or_root_locked(); (ssid) = 0; }); \ + (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ + if (!((ss) = cgroup_subsys[(ssid)])) { } \ else/**
@@ -4911,6 +4920,7 @@ int __init_or_module cgroup_load_subsys(cgroup_init_cftsets (ss);mutex_lock (&cgroup_mutex); +mutex_lock (&cgroup_root_mutex); cgroup_subsys[ss->subsys_id] = ss;/*
@@ -4966,10 +4976,12 @@ int __init_or_module cgroup_load_subsys( goto err_unload;/* success! */ +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex);return 0 ; err_unload: +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex);/* @ss can't be mounted here as try_module_get() would fail */ cgroup_unload_subsys (ss);
@@ -4999,6 +5011,7 @@ void cgroup_unload_subsys(struct cgroup_BUG_ON (ss->root != &cgroup_dummy_root);mutex_lock (&cgroup_mutex); +mutex_lock (&cgroup_root_mutex);offline_css (cgroup_css (cgroup_dummy_top, ss));
@@ -5037,6 +5050,7 @@ void cgroup_unload_subsys(struct cgroup_ ss->css_free (cgroup_css (cgroup_dummy_top, ss));RCU_INIT_POINTER (cgroup_dummy_top->subsys[ss->subsys_id],NULL ); +mutex_unlock (&cgroup_root_mutex);mutex_unlock (&cgroup_mutex); }EXPORT_SYMBOL_GPL (cgroup_unload_subsys);
Tejun Heo
maintainerPATCH 4/9 cgroup: move css_id commit from cgroup_populate_dir() to online_css()
In reply to Tejun Heocss_id should be committed after a css is brought online fully. This is currently done form cgroup_populate_dir() but we're gonna reorder operations such that cgroup_populate_dir() is called before css is onlined. Let's move css_id commit from cgroup_populate_dir() to online_css().
This change makes it possible for cgroup creation to fail after css_id is committed; however, as css is already fully initialized, the cleanup isn't different from the cgroup being removed.
--- kernel/cgroup.c | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-)
kernel/cgroup.c +25 -28
@@ -4244,7 +4244,7 @@ static struct cftype cgroup_base_files[] = {static int cgroup_populate_dir (struct cgroup *cgrp,unsigned long subsys_mask) {struct cgroup_subsys *ss; -int i, ret =0 ; +int i, ret;/* process cftsets of each subsystem */ for_each_subsys (ss, i) {
@@ -4255,29 +4255,14 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask)list_for_each_entry (set, &ss->cftsets, node) { ret =cgroup_addrm_files (cgrp, set->cfts, true); -if (ret <0 ) - goto err; +if (ret <0 ) { +cgroup_clear_dir (cgrp, subsys_mask); +return ret; + } } } -/* This cgroup is ready now */ -for_each_root_subsys (cgrp->root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); -struct css_id *id =rcu_dereference_protected (css->id, true); - -/* -* Update id->css pointer and make this css visible from -* CSS ID functions. This pointer will be dereferened -* from RCU-read-side without locks. -*/ -if (id) -rcu_assign_pointer (id->css, css); - } -return 0 ; -err: -cgroup_clear_dir (cgrp, subsys_mask); -return ret; }/*
@@ -4356,18 +4341,30 @@ static void init_css(struct cgroup_subsys_state *css, struct cgroup_subsys *ss,static int online_css (struct cgroup_subsys_state *css) {struct cgroup_subsys *ss = css->ss; -int ret =0 ; +struct css_id *id =rcu_dereference_protected (css->id, true); +int ret;lockdep_assert_held (&cgroup_mutex); -if (ss->css_online) +if (ss->css_online) { ret = ss->css_online (css); -if (!ret) { - css->flags |=CSS_ONLINE ; - css->cgroup->nr_css++; -rcu_assign_pointer (css->cgroup->subsys[ss->subsys_id], css); +if (ret) +return ret; } -return ret; + + css->flags |=CSS_ONLINE ; + css->cgroup->nr_css++; +rcu_assign_pointer (css->cgroup->subsys[ss->subsys_id], css); + +/* +* Update id->css pointer and make this css visible from CSS ID +* functions. This pointer will be dereferened from RCU-read-side +* without locks. +*/ +if (id) +rcu_assign_pointer (id->css, css); + +return 0 ; }/* if the CSS is online, invoke ->css_offline() on it and mark it offline */
@@ -5678,7 +5675,7 @@ static int alloc_css_id(struct cgroup_subsys_state *child_css) child_id->stack[depth] = child_id->id;/* * child_id->css pointer will be set after this cgroup is available -* see cgroup_populate_dir() +* see online_css() */ rcu_assign_pointer (child_css->id, child_id);
Signature · 1 line
1.8.3.1
Tejun Heo
maintainerPATCH 5/9 cgroup: reorder operations in cgroup_create()
In reply to Tejun Heocgroup_create() currently does the followings.
1. alloc cgroup
2. alloc css's
3. create the directory and commit to cgroup creation
4. online css's
5. create cgroup and css files
The sequence performs allocations before other operations but it doesn't buy anything because each of the above steps may fail and should be unrollable. Reorganize the sequence such that cgroup operations are done before css operations.
1. alloc cgroup
2. create the directory and files and commit to cgroup creation
3. alloc css's
4. create files for and online css's
This simplifies the code a bit and enables further simplification and separating out css creation from cgroup creation which is necessary for the planned unified hierarchy where css's will be created and destroyed dynamically across the lifetime of a cgroup.
--- kernel/cgroup.c | 78 +++++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 41 deletions(-)
kernel/cgroup.c +37 -41
@@ -4456,52 +4456,66 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,if (test_bit (CGRP_CPUSET_CLONE_CHILDREN , &parent->flags))set_bit (CGRP_CPUSET_CLONE_CHILDREN , &cgrp->flags); +/* +* Create directory. cgroup_create_file() returns with the new +* directory locked on success so that it can be populated without +* dropping cgroup_mutex. +*/ + err =cgroup_create_file (dentry,S_IFDIR | mode, sb); +if (err <0 ) + goto err_unlock; +lockdep_assert_held (&dentry->d_inode->i_mutex); + + cgrp->serial_nr = cgroup_serial_nr_next++; + +/* allocation complete, commit to creation */ +list_add_tail_rcu (&cgrp->sibling, &cgrp->parent->children); + root->number_of_cgroups++; + +/* hold a ref to the parent's dentry */ +dget (parent->dentry); + +/* +* @cgrp is now fully operational. If something fails after this +* point, it'll be released via the normal destruction path. +*/ +idr_replace (&root->cgroup_idr, cgrp, cgrp->id); + + err =cgroup_addrm_files (cgrp, cgroup_base_files, true); +if (err) + goto err_destroy; +for_each_root_subsys (root, ss) {struct cgroup_subsys_state *css; css = ss->css_alloc (cgroup_css (parent, ss));if (IS_ERR (css)) { err =PTR_ERR (css); - goto err_free_all; + goto err_destroy; } css_ar[ss->subsys_id] = css; err =percpu_ref_init (&css->refcnt, css_release);if (err) - goto err_free_all; + goto err_destroy;init_css (css, ss, cgrp);if (ss->use_id) { err =alloc_css_id (css);if (err) - goto err_free_all; + goto err_destroy; } } -/* -* Create directory. cgroup_create_file() returns with the new -* directory locked on success so that it can be populated without -* dropping cgroup_mutex. -*/ - err =cgroup_create_file (dentry,S_IFDIR | mode, sb); -if (err <0 ) - goto err_free_all; -lockdep_assert_held (&dentry->d_inode->i_mutex); - - cgrp->serial_nr = cgroup_serial_nr_next++; - -/* allocation complete, commit to creation */ -list_add_tail_rcu (&cgrp->sibling, &cgrp->parent->children); - root->number_of_cgroups++; - -/* hold a ref to the parent's dentry */ -dget (parent->dentry); -/* creation succeeded, notify subsystems */ for_each_root_subsys (root, ss) {struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; + err =cgroup_populate_dir (cgrp,1 << ss->subsys_id); +if (err) + goto err_destroy; + err =online_css (css);if (err) goto err_destroy;
@@ -4523,30 +4537,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, } } -idr_replace (&root->cgroup_idr, cgrp, cgrp->id); - - err =cgroup_addrm_files (cgrp, cgroup_base_files, true); -if (err) - goto err_destroy; - - err =cgroup_populate_dir (cgrp, root->subsys_mask); -if (err) - goto err_destroy; -mutex_unlock (&cgroup_mutex);mutex_unlock (&cgrp->dentry->d_inode->i_mutex);return 0 ; -err_free_all: -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; - -if (css) { -percpu_ref_cancel_init (&css->refcnt); - ss->css_free (css); - } - } +err_unlock:mutex_unlock (&cgroup_mutex);/* Release the reference count that we took on the superblock */ deactivate_super (sb);
Signature · 1 line
1.8.3.1
Tejun Heo
maintainerPATCH 6/9 cgroup: combine css handling loops in cgroup_create()
In reply to Tejun HeoNow that css operations in cgroup_create() are back-to-back, there isn't much point in allocating css's in one loop and onlining them in another. Merge the two loops so that a css is allocated and onlined on each iteration.
css_ar[] is no longer necessary and replaced with a single pointer. This also simplifies the error handling path.
--- kernel/cgroup.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-)
kernel/cgroup.c +7 -18
@@ -4396,7 +4396,7 @@ static void offline_css(struct cgroup_subsys_state *css)static long cgroup_create (struct cgroup *parent,struct dentry *dentry,umode_t mode) { -struct cgroup_subsys_state *css_ar[CGROUP_SUBSYS_COUNT ] = { }; +struct cgroup_subsys_state *css =NULL ;struct cgroup *cgrp;struct cgroup_name *name;struct cgroupfs_root *root = parent->root;
@@ -4485,15 +4485,14 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,if (err) goto err_destroy; +/* let's create and online css's */ for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css; - css = ss->css_alloc (cgroup_css (parent, ss));if (IS_ERR (css)) { err =PTR_ERR (css); + css =NULL ; goto err_destroy; } - css_ar[ss->subsys_id] = css; err =percpu_ref_init (&css->refcnt, css_release);if (err)
@@ -4506,11 +4505,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,if (err) goto err_destroy; } - } - -/* creation succeeded, notify subsystems */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; err =cgroup_populate_dir (cgrp,1 << ss->subsys_id);if (err)
@@ -4520,12 +4514,11 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,if (err) goto err_destroy; -/* each css holds a ref to the cgroup's dentry and parent css */ dget (dentry);css_get (css->parent);/* mark it consumed for error path */ - css_ar[ss->subsys_id] =NULL ; + css =NULL ;if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && parent->parent) {
@@ -4555,13 +4548,9 @@ err_free_cgrp:return err; err_destroy: -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; - -if (css) { -percpu_ref_cancel_init (&css->refcnt); - ss->css_free (css); - } +if (css) { +percpu_ref_cancel_init (&css->refcnt); + css->ss->css_free (css); }cgroup_destroy_locked (cgrp);mutex_unlock (&cgroup_mutex);
Signature · 1 line
1.8.3.1
Tejun Heo
maintainerPATCH 7/9 cgroup: factor out cgroup_subsys_state creation into create_css()
In reply to Tejun HeoNow that all opertations to create a css (cgroup_subsys_state) are collected into a single loop in cgroup_create(), it's easy to factor it out into its own function. Factor out css creation into create_css(). This makes the code easier to follow and will enable decoupling css creation from cgroup creation which is necessary for the planned unified hierarchy.
--- kernel/cgroup.c | 107 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 44 deletions(-)
kernel/cgroup.c +63 -44
@@ -4385,6 +4385,68 @@ static void offline_css(struct cgroup_subsys_state *css)RCU_INIT_POINTER (css->cgroup->subsys[ss->subsys_id], css); } +/** +* create_css - create a cgroup_subsys_state +* @cgrp: the cgroup new css will be associated with +* @ss: the subsys of new css +* +* Create a new css associated with @cgrp - @ss pair. On success, the new +* css is online and installed in @cgrp with all interface files created. +* Returns 0 on success, -errno on failure. +*/ +static int create_css (struct cgroup *cgrp,struct cgroup_subsys *ss) +{ +struct cgroup *parent = cgrp->parent; +struct cgroup_subsys_state *css; +int err; + +lockdep_assert_held (&cgrp->dentry->d_inode->i_mutex); +lockdep_assert_held (&cgroup_mutex); + + css = ss->css_alloc (cgroup_css (parent, ss)); +if (IS_ERR (css)) +return PTR_ERR (css); + + err =percpu_ref_init (&css->refcnt, css_release); +if (err) + goto err_free; + +init_css (css, ss, cgrp); + +if (ss->use_id) { + err =alloc_css_id (css); +if (err) + goto err_free; + } + + err =cgroup_populate_dir (cgrp,1 << ss->subsys_id); +if (err) + goto err_free; + + err =online_css (css); +if (err) + goto err_free; + +dget (cgrp->dentry); +css_get (css->parent); + +if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && + parent->parent) { +pr_warning ("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n" , + current->comm, current->pid, ss->name); +if (!strcmp (ss->name,"memory" )) +pr_warning ("cgroup: \"memory\" requires setting use_hierarchy to 1 on the root.\n" ); + ss->warned_broken_hierarchy = true; + } + +return 0 ; + +err_free: +percpu_ref_cancel_init (&css->refcnt); + ss->css_free (css); +return err; +} +/* * cgroup_create - create a cgroup * @parent: cgroup that will be parent of the new cgroup
@@ -4396,7 +4458,6 @@ static void offline_css(struct cgroup_subsys_state *css)static long cgroup_create (struct cgroup *parent,struct dentry *dentry,umode_t mode) { -struct cgroup_subsys_state *css =NULL ;struct cgroup *cgrp;struct cgroup_name *name;struct cgroupfs_root *root = parent->root;
@@ -4487,47 +4548,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,/* let's create and online css's */ for_each_root_subsys (root, ss) { - css = ss->css_alloc (cgroup_css (parent, ss)); -if (IS_ERR (css)) { - err =PTR_ERR (css); - css =NULL ; - goto err_destroy; - } - - err =percpu_ref_init (&css->refcnt, css_release); -if (err) - goto err_destroy; - -init_css (css, ss, cgrp); - -if (ss->use_id) { - err =alloc_css_id (css); -if (err) - goto err_destroy; - } - - err =cgroup_populate_dir (cgrp,1 << ss->subsys_id); -if (err) - goto err_destroy; - - err =online_css (css); + err =create_css (cgrp, ss);if (err) goto err_destroy; - -dget (dentry); -css_get (css->parent); - -/* mark it consumed for error path */ - css =NULL ; - -if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && - parent->parent) { -pr_warning ("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n" , - current->comm, current->pid, ss->name); -if (!strcmp (ss->name,"memory" )) -pr_warning ("cgroup: \"memory\" requires setting use_hierarchy to 1 on the root.\n" ); - ss->warned_broken_hierarchy = true; - } }mutex_unlock (&cgroup_mutex);
@@ -4548,10 +4571,6 @@ err_free_cgrp:return err; err_destroy: -if (css) { -percpu_ref_cancel_init (&css->refcnt); - css->ss->css_free (css); - }cgroup_destroy_locked (cgrp);mutex_unlock (&cgroup_mutex);mutex_unlock (&dentry->d_inode->i_mutex);
Signature · 1 line
1.8.3.1
A message that is not in the archive (sent off-list or not yet received): 1377723829-22814-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
PATCH 7/9 cgroup: factor out cgroup_subsys_state creation into create_css()
Now that all opertations to create a css (cgroup_subsys_state) are collected into a single loop in cgroup_create(), it's easy to factor it out into its own function. Factor out css creation into create_css(). This makes the code easier to follow and will enable decoupling css creation from cgroup creation which is necessary for the planned unified hierarchy.
--- kernel/cgroup.c | 107 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 44 deletions(-)
kernel/cgroup.c +63 -44
@@ -4385,6 +4385,68 @@ static void offline_css(struct cgroup_subsys_state *css)RCU_INIT_POINTER (css->cgroup->subsys[ss->subsys_id], css); } +/** +* create_css - create a cgroup_subsys_state +* @cgrp: the cgroup new css will be associated with +* @ss: the subsys of new css +* +* Create a new css associated with @cgrp - @ss pair. On success, the new +* css is online and installed in @cgrp with all interface files created. +* Returns 0 on success, -errno on failure. +*/ +static int create_css (struct cgroup *cgrp,struct cgroup_subsys *ss) +{ +struct cgroup *parent = cgrp->parent; +struct cgroup_subsys_state *css; +int err; + +lockdep_assert_held (&cgrp->dentry->d_inode->i_mutex); +lockdep_assert_held (&cgroup_mutex); + + css = ss->css_alloc (cgroup_css (parent, ss)); +if (IS_ERR (css)) +return PTR_ERR (css); + + err =percpu_ref_init (&css->refcnt, css_release); +if (err) + goto err_free; + +init_css (css, ss, cgrp); + +if (ss->use_id) { + err =alloc_css_id (css); +if (err) + goto err_free; + } + + err =cgroup_populate_dir (cgrp,1 << ss->subsys_id); +if (err) + goto err_free; + + err =online_css (css); +if (err) + goto err_free; + +dget (cgrp->dentry); +css_get (css->parent); + +if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && + parent->parent) { +pr_warning ("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n" , + current->comm, current->pid, ss->name); +if (!strcmp (ss->name,"memory" )) +pr_warning ("cgroup: \"memory\" requires setting use_hierarchy to 1 on the root.\n" ); + ss->warned_broken_hierarchy = true; + } + +return 0 ; + +err_free: +percpu_ref_cancel_init (&css->refcnt); + ss->css_free (css); +return err; +} +/* * cgroup_create - create a cgroup * @parent: cgroup that will be parent of the new cgroup
@@ -4396,7 +4458,6 @@ static void offline_css(struct cgroup_subsys_state *css)static long cgroup_create (struct cgroup *parent,struct dentry *dentry,umode_t mode) { -struct cgroup_subsys_state *css =NULL ;struct cgroup *cgrp;struct cgroup_name *name;struct cgroupfs_root *root = parent->root;
@@ -4487,47 +4548,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,/* let's create and online css's */ for_each_root_subsys (root, ss) { - css = ss->css_alloc (cgroup_css (parent, ss)); -if (IS_ERR (css)) { - err =PTR_ERR (css); - css =NULL ; - goto err_destroy; - } - - err =percpu_ref_init (&css->refcnt, css_release); -if (err) - goto err_destroy; - -init_css (css, ss, cgrp); - -if (ss->use_id) { - err =alloc_css_id (css); -if (err) - goto err_destroy; - } - - err =cgroup_populate_dir (cgrp,1 << ss->subsys_id); -if (err) - goto err_destroy; - - err =online_css (css); + err =create_css (cgrp, ss);if (err) goto err_destroy; - -dget (dentry); -css_get (css->parent); - -/* mark it consumed for error path */ - css =NULL ; - -if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && - parent->parent) { -pr_warning ("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n" , - current->comm, current->pid, ss->name); -if (!strcmp (ss->name,"memory" )) -pr_warning ("cgroup: \"memory\" requires setting use_hierarchy to 1 on the root.\n" ); - ss->warned_broken_hierarchy = true; - } }mutex_unlock (&cgroup_mutex);
@@ -4548,10 +4571,6 @@ err_free_cgrp:return err; err_destroy: -if (css) { -percpu_ref_cancel_init (&css->refcnt); - css->ss->css_free (css); - }cgroup_destroy_locked (cgrp);mutex_unlock (&cgroup_mutex);mutex_unlock (&dentry->d_inode->i_mutex);
Signature · 1 line
1.8.3.1
PATCH 9/9 cgroup: remove for_each_root_subsys()
In reply to a message not in the archiveAfter the previous patch which introduced for_each_css(), for_each_root_subsys() only has two users left. This patch replaces it with for_each_subsys() + explicit subsys_mask testing and remove for_each_root_subsys() along with cgroupfs_root->subsys_list handling.
This patch doesn't introduce any behavior changes.
--- include/linux/cgroup.h | 10 ++-------- kernel/cgroup.c | 37 +++++++++++++++---------------------- 2 files changed, 17 insertions(+), 30 deletions(-)
include/linux/cgroup.h +2 -8
@@ -320,9 +320,6 @@ struct cgroupfs_root {/* Unique id for this hierarchy. */ int hierarchy_id; -/* A list running through the attached subsystems */ -struct list_head subsys_list; -/* The root cgroup for this hierarchy */ struct cgroup top_cgroup;
@@ -636,12 +633,9 @@ struct cgroup_subsys {#define MAX_CGROUP_TYPE_NAMELEN 32const char *name; -/* -* Link to parent, and list entry in parent's children. -* Protected by cgroup_lock() -*/ +/* link to parent, protected by cgroup_lock() */ struct cgroupfs_root *root; -struct list_head sibling; +/* used when use_id == true */ struct idr idr;spinlock_t id_lock;
kernel/cgroup.c +15 -22
@@ -331,10 +331,6 @@ static int notify_on_release(const struct cgroup *cgrp)for ((i) =0 ; (i) <CGROUP_BUILTIN_SUBSYS_COUNT && \ (((ss) = cgroup_subsys[i]) || true); (i)++) -/* iterate each subsystem attached to a hierarchy */ -#define for_each_root_subsys (root, ss) \ - list_for_each_entry((ss), &(root)->subsys_list, sibling) - /* iterate across the active hierarchies */#define for_each_active_root (root) \ list_for_each_entry((root), &cgroup_roots, root_list)
@@ -1096,7 +1092,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, cgroup_css(cgroup_dummy_top, ss));cgroup_css (cgrp, ss)->cgroup = cgrp; -list_move (&ss->sibling, &root->subsys_list); ss->root = root;if (ss->bind) ss->bind (cgroup_css (cgrp, ss));
@@ -1115,7 +1110,6 @@ static int rebind_subsystems(struct cgroupfs_root *root,RCU_INIT_POINTER (cgrp->subsys[i],NULL ); cgroup_subsys[i]->root = &cgroup_dummy_root; -list_move (&ss->sibling, &cgroup_dummy_root.subsys_list);/* subsystem is now free - drop reference on module */ module_put (ss->module);
@@ -1142,10 +1136,12 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) {struct cgroupfs_root *root = dentry->d_sb->s_fs_info;struct cgroup_subsys *ss; +int ssid;mutex_lock (&cgroup_root_mutex); -for_each_root_subsys (root, ss) -seq_printf (seq,",%s" , ss->name); +for_each_subsys (ss, ssid) +if (root->subsys_mask & (1 << ssid)) +seq_printf (seq,",%s" , ss->name);if (root->flags &CGRP_ROOT_SANE_BEHAVIOR )seq_puts (seq,",sane_behavior" );if (root->flags &CGRP_ROOT_NOPREFIX )
@@ -1417,7 +1413,6 @@ static void init_cgroup_root(struct cgroupfs_root *root) {struct cgroup *cgrp = &root->top_cgroup; -INIT_LIST_HEAD (&root->subsys_list);INIT_LIST_HEAD (&root->root_list); root->number_of_cgroups =1 ; cgrp->root = root;
@@ -4469,7 +4464,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,struct cgroup *cgrp;struct cgroup_name *name;struct cgroupfs_root *root = parent->root; -int err =0 ; +int ssid, err =0 ;struct cgroup_subsys *ss;struct super_block *sb = root->sb;
@@ -4555,10 +4550,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, goto err_destroy;/* let's create and online css's */ -for_each_root_subsys (root, ss) { - err =create_css (cgrp, ss); -if (err) - goto err_destroy; +for_each_subsys (ss, ssid) { +if (root->subsys_mask & (1 << ssid)) { + err =create_css (cgrp, ss); +if (err) + goto err_destroy; + } }mutex_unlock (&cgroup_mutex);
@@ -4850,7 +4847,6 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)cgroup_init_cftsets (ss);/* Create the top cgroup state for this subsystem */ -list_add (&ss->sibling, &cgroup_dummy_root.subsys_list); ss->root = &cgroup_dummy_root; css = ss->css_alloc (cgroup_css (cgroup_dummy_top, ss));/* We don't handle early failures gracefully */
@@ -4940,7 +4936,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)return PTR_ERR (css); } -list_add (&ss->sibling, &cgroup_dummy_root.subsys_list); ss->root = &cgroup_dummy_root;/* our new subsystem will be attached to the dummy hierarchy. */
@@ -5025,9 +5020,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)/* deassign the subsys_id */ cgroup_subsys[ss->subsys_id] =NULL ; -/* remove subsystem from the dummy root's list of subsystems */ -list_del_init (&ss->sibling); -/* * disentangle the css from all css_sets attached to the dummy * top. as in loading, we need to pay our respects to the hashtable
@@ -5202,11 +5194,12 @@ int proc_cgroup_show(struct seq_file *m, void *v)for_each_active_root (root) {struct cgroup_subsys *ss;struct cgroup *cgrp; -int count =0 ; +int ssid, count =0 ;seq_printf (m,"%d:" , root->hierarchy_id); -for_each_root_subsys (root, ss) -seq_printf (m,"%s%s" , count++ ?"," :"" , ss->name); +for_each_subsys (ss, ssid) +if (root->subsys_mask & (1 << ssid)) +seq_printf (m,"%s%s" , count++ ?"," :"" , ss->name);if (strlen (root->name))seq_printf (m,"%sname=%s" , count ?"," :"" , root->name);
Signature · 1 line
1.8.3.1
Tejun Heo
maintainerPATCH 8/9 cgroup: implement for_each_css()
In reply to Tejun HeoThere are enough places where css's of a cgroup are iterated, which currently uses for_each_root_subsys() + explicit cgroup_css(). This patch implements for_each_css() and replaces the above combination with it.
This patch doesn't introduce any behavior changes.
--- kernel/cgroup.c | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-)
kernel/cgroup.c +31 -22
@@ -289,6 +289,21 @@ static int notify_on_release(const struct cgroup *cgrp) }/** +* for_each_css - iterate all css's of a cgroup +* @css: the iteration cursor +* @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end +* @cgrp: the target cgroup to iterate css's of +* +* Should be called under cgroup_mutex. +*/ +#define for_each_css (css, ssid, cgrp) \ + for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ + if (!((css) = rcu_dereference_check( \ + (cgrp)->subsys[(ssid)], \ + lockdep_is_held(&cgroup_mutex)))) { } \ + else + +/** * for_each_subsys - iterate all loaded cgroup subsystems * @ss: the iteration cursor * @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end
@@ -2007,8 +2022,8 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk, bool threadgroup) {int retval, i, group_size; -struct cgroup_subsys *ss, *failed_ss =NULL ;struct cgroupfs_root *root = cgrp->root; +struct cgroup_subsys_state *css, *failed_css =NULL ;/* threadgroup list cursor and array */ struct task_struct *leader = tsk;struct task_and_cgroup *tc;
@@ -2081,13 +2096,11 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,/* * step 1: check that we can legitimately attach to the cgroup. */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); - -if (ss->can_attach) { - retval = ss->can_attach (css, &tset); +for_each_css (css, i, cgrp) { +if (css->ss->can_attach) { + retval = css->ss->can_attach (css, &tset);if (retval) { - failed_ss = ss; + failed_css = css; goto out_cancel_attach; } }
@@ -2123,12 +2136,9 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,/* * step 4: do subsystem attach callbacks. */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); - -if (ss->attach) - ss->attach (css, &tset); - } +for_each_css (css, i, cgrp) +if (css->ss->attach) + css->ss->attach (css, &tset);/* * step 5: success! and cleanup
@@ -2145,13 +2155,11 @@ out_put_css_set_refs: } out_cancel_attach:if (retval) { -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); - -if (ss == failed_ss) +for_each_css (css, i, cgrp) { +if (css == failed_css)break ; -if (ss->cancel_attach) - ss->cancel_attach (css, &tset); +if (css->ss->cancel_attach) + css->ss->cancel_attach (css, &tset); } } out_free_group_list:
@@ -4694,8 +4702,9 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) {struct dentry *d = cgrp->dentry;struct cgroup_event *event, *tmp; -struct cgroup_subsys *ss; +struct cgroup_subsys_state *css;bool empty; +int ssid;lockdep_assert_held (&d->d_inode->i_mutex);lockdep_assert_held (&cgroup_mutex);
@@ -4715,8 +4724,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)* will be invoked to perform the rest of destruction once the * percpu refs of all css's are confirmed to be killed. */ -for_each_root_subsys (cgrp->root, ss) -kill_css (cgroup_css (cgrp, ss)); +for_each_css (css, ssid, cgrp) +kill_css (css);/* * Mark @cgrp dead. This prevents further task migration and child
Signature · 1 line
1.8.3.1
Tejun Heo
maintainerPATCH v2 8/9 cgroup: implement for_each_css()
There are enough places where css's of a cgroup are iterated, which currently uses for_each_root_subsys() + explicit cgroup_css(). This patch implements for_each_css() and replaces the above combination with it.
This patch doesn't introduce any behavior changes.
v2: Updated to apply cleanly on top of v2 of "cgroup: fix css leaks on
online_css() failure"
--- kernel/cgroup.c | 57 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 26 deletions(-)
kernel/cgroup.c +31 -26
@@ -297,6 +297,21 @@ static int notify_on_release(const struc }/** +* for_each_css - iterate all css's of a cgroup +* @css: the iteration cursor +* @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end +* @cgrp: the target cgroup to iterate css's of +* +* Should be called under cgroup_mutex. +*/ +#define for_each_css (css, ssid, cgrp) \ + for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ + if (!((css) = rcu_dereference_check( \ + (cgrp)->subsys[(ssid)], \ + lockdep_is_held(&cgroup_mutex)))) { } \ + else + +/** * for_each_subsys - iterate all loaded cgroup subsystems * @ss: the iteration cursor * @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end
@@ -2013,8 +2028,8 @@ static int cgroup_attach_task(struct cgr bool threadgroup) {int retval, i, group_size; -struct cgroup_subsys *ss, *failed_ss =NULL ;struct cgroupfs_root *root = cgrp->root; +struct cgroup_subsys_state *css, *failed_css =NULL ;/* threadgroup list cursor and array */ struct task_struct *leader = tsk;struct task_and_cgroup *tc;
@@ -2087,13 +2102,11 @@ static int cgroup_attach_task(struct cgr/* * step 1: check that we can legitimately attach to the cgroup. */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); - -if (ss->can_attach) { - retval = ss->can_attach (css, &tset); +for_each_css (css, i, cgrp) { +if (css->ss->can_attach) { + retval = css->ss->can_attach (css, &tset);if (retval) { - failed_ss = ss; + failed_css = css; goto out_cancel_attach; } }
@@ -2129,12 +2142,9 @@ static int cgroup_attach_task(struct cgr/* * step 4: do subsystem attach callbacks. */ -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); - -if (ss->attach) - ss->attach (css, &tset); - } +for_each_css (css, i, cgrp) +if (css->ss->attach) + css->ss->attach (css, &tset);/* * step 5: success! and cleanup
@@ -2151,13 +2161,11 @@ out_put_css_set_refs: } out_cancel_attach:if (retval) { -for_each_root_subsys (root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); - -if (ss == failed_ss) +for_each_css (css, i, cgrp) { +if (css == failed_css)break ; -if (ss->cancel_attach) - ss->cancel_attach (css, &tset); +if (css->ss->cancel_attach) + css->ss->cancel_attach (css, &tset); } } out_free_group_list:
@@ -4700,8 +4708,9 @@ static int cgroup_destroy_locked(struct {struct dentry *d = cgrp->dentry;struct cgroup_event *event, *tmp; -struct cgroup_subsys *ss; +struct cgroup_subsys_state *css;bool empty; +int ssid;lockdep_assert_held (&d->d_inode->i_mutex);lockdep_assert_held (&cgroup_mutex);
@@ -4721,12 +4730,8 @@ static int cgroup_destroy_locked(struct* will be invoked to perform the rest of destruction once the * percpu refs of all css's are confirmed to be killed. */ -for_each_root_subsys (cgrp->root, ss) { -struct cgroup_subsys_state *css =cgroup_css (cgrp, ss); - -if (css) -kill_css (css); - } +for_each_css (css, ssid, cgrp) +kill_css (css);/* * Mark @cgrp dead. This prevents further task migration and child
Tejun Heo
maintainerPATCH 9/9 cgroup: remove for_each_root_subsys()
In reply to Tejun HeoAfter the previous patch which introduced for_each_css(), for_each_root_subsys() only has two users left. This patch replaces it with for_each_subsys() + explicit subsys_mask testing and remove for_each_root_subsys() along with cgroupfs_root->subsys_list handling.
This patch doesn't introduce any behavior changes.
--- include/linux/cgroup.h | 10 ++-------- kernel/cgroup.c | 37 +++++++++++++++---------------------- 2 files changed, 17 insertions(+), 30 deletions(-)
include/linux/cgroup.h +2 -8
@@ -320,9 +320,6 @@ struct cgroupfs_root {/* Unique id for this hierarchy. */ int hierarchy_id; -/* A list running through the attached subsystems */ -struct list_head subsys_list; -/* The root cgroup for this hierarchy */ struct cgroup top_cgroup;
@@ -636,12 +633,9 @@ struct cgroup_subsys {#define MAX_CGROUP_TYPE_NAMELEN 32const char *name; -/* -* Link to parent, and list entry in parent's children. -* Protected by cgroup_lock() -*/ +/* link to parent, protected by cgroup_lock() */ struct cgroupfs_root *root; -struct list_head sibling; +/* used when use_id == true */ struct idr idr;spinlock_t id_lock;
kernel/cgroup.c +15 -22
@@ -331,10 +331,6 @@ static int notify_on_release(const struct cgroup *cgrp)for ((i) =0 ; (i) <CGROUP_BUILTIN_SUBSYS_COUNT && \ (((ss) = cgroup_subsys[i]) || true); (i)++) -/* iterate each subsystem attached to a hierarchy */ -#define for_each_root_subsys (root, ss) \ - list_for_each_entry((ss), &(root)->subsys_list, sibling) - /* iterate across the active hierarchies */#define for_each_active_root (root) \ list_for_each_entry((root), &cgroup_roots, root_list)
@@ -1096,7 +1092,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, cgroup_css(cgroup_dummy_top, ss));cgroup_css (cgrp, ss)->cgroup = cgrp; -list_move (&ss->sibling, &root->subsys_list); ss->root = root;if (ss->bind) ss->bind (cgroup_css (cgrp, ss));
@@ -1115,7 +1110,6 @@ static int rebind_subsystems(struct cgroupfs_root *root,RCU_INIT_POINTER (cgrp->subsys[i],NULL ); cgroup_subsys[i]->root = &cgroup_dummy_root; -list_move (&ss->sibling, &cgroup_dummy_root.subsys_list);/* subsystem is now free - drop reference on module */ module_put (ss->module);
@@ -1142,10 +1136,12 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) {struct cgroupfs_root *root = dentry->d_sb->s_fs_info;struct cgroup_subsys *ss; +int ssid;mutex_lock (&cgroup_root_mutex); -for_each_root_subsys (root, ss) -seq_printf (seq,",%s" , ss->name); +for_each_subsys (ss, ssid) +if (root->subsys_mask & (1 << ssid)) +seq_printf (seq,",%s" , ss->name);if (root->flags &CGRP_ROOT_SANE_BEHAVIOR )seq_puts (seq,",sane_behavior" );if (root->flags &CGRP_ROOT_NOPREFIX )
@@ -1417,7 +1413,6 @@ static void init_cgroup_root(struct cgroupfs_root *root) {struct cgroup *cgrp = &root->top_cgroup; -INIT_LIST_HEAD (&root->subsys_list);INIT_LIST_HEAD (&root->root_list); root->number_of_cgroups =1 ; cgrp->root = root;
@@ -4469,7 +4464,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,struct cgroup *cgrp;struct cgroup_name *name;struct cgroupfs_root *root = parent->root; -int err =0 ; +int ssid, err =0 ;struct cgroup_subsys *ss;struct super_block *sb = root->sb;
@@ -4555,10 +4550,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, goto err_destroy;/* let's create and online css's */ -for_each_root_subsys (root, ss) { - err =create_css (cgrp, ss); -if (err) - goto err_destroy; +for_each_subsys (ss, ssid) { +if (root->subsys_mask & (1 << ssid)) { + err =create_css (cgrp, ss); +if (err) + goto err_destroy; + } }mutex_unlock (&cgroup_mutex);
@@ -4850,7 +4847,6 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)cgroup_init_cftsets (ss);/* Create the top cgroup state for this subsystem */ -list_add (&ss->sibling, &cgroup_dummy_root.subsys_list); ss->root = &cgroup_dummy_root; css = ss->css_alloc (cgroup_css (cgroup_dummy_top, ss));/* We don't handle early failures gracefully */
@@ -4940,7 +4936,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)return PTR_ERR (css); } -list_add (&ss->sibling, &cgroup_dummy_root.subsys_list); ss->root = &cgroup_dummy_root;/* our new subsystem will be attached to the dummy hierarchy. */
@@ -5025,9 +5020,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)/* deassign the subsys_id */ cgroup_subsys[ss->subsys_id] =NULL ; -/* remove subsystem from the dummy root's list of subsystems */ -list_del_init (&ss->sibling); -/* * disentangle the css from all css_sets attached to the dummy * top. as in loading, we need to pay our respects to the hashtable
@@ -5202,11 +5194,12 @@ int proc_cgroup_show(struct seq_file *m, void *v)for_each_active_root (root) {struct cgroup_subsys *ss;struct cgroup *cgrp; -int count =0 ; +int ssid, count =0 ;seq_printf (m,"%d:" , root->hierarchy_id); -for_each_root_subsys (root, ss) -seq_printf (m,"%s%s" , count++ ?"," :"" , ss->name); +for_each_subsys (ss, ssid) +if (root->subsys_mask & (1 << ssid)) +seq_printf (m,"%s%s" , count++ ?"," :"" , ss->name);if (strlen (root->name))seq_printf (m,"%sname=%s" , count ?"," :"" , root->name);
Signature · 1 line
1.8.3.1
Quoted 10 lines · Tejun Heo
Hello,
For unified hierarchy, a css's (
cgroup_subsys_state) lifetime will be different from that of the associated cgroup. css's may be created and destroyed dynamically over the lifetime of a single cgroup. The previous changes decoupled css destruction from cgroup's. This patchset decouples css creation from cgroup's.This patchset contains the following nine patches.
Quoted 10 lines
0001-cgroup-fix-css-leaks-on-online_css-failure.patch 0002-cgroup-css-iterations-and-css_from_dir-are-safe-unde.patch 0003-cgroup-make-for_each_subsys-useable-under-cgroup_roo.patch 0004-cgroup-move-css_id-commit-from-cgroup_populate_dir-t.patch 0005-cgroup-reorder-operations-in-cgroup_create.patch 0006-cgroup-combine-css-handling-loops-in-cgroup_create.patch 0007-cgroup-factor-out-cgroup_subsys_state-creation-into-.patch 0008-cgroup-implement-for_each_css.patch 0009-cgroup-remove-for_each_root_subsys.patch