diff options
-rw-r--r-- | kernel/cgroup.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 5385839e727b..dcb06e181ce4 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4138,19 +4138,21 @@ static void css_release_work_fn(struct work_struct *work) struct cgroup_subsys *ss = css->ss; struct cgroup *cgrp = css->cgroup; + mutex_lock(&cgroup_mutex); + + list_del_rcu(&css->sibling); + if (ss) { /* css release path */ cgroup_idr_remove(&ss->css_idr, css->id); } else { /* cgroup release path */ - mutex_lock(&cgroup_mutex); - list_del_rcu(&cgrp->self.sibling); - mutex_unlock(&cgroup_mutex); - cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id); cgrp->id = -1; } + mutex_unlock(&cgroup_mutex); + call_rcu(&css->rcu_head, css_free_rcu_fn); } @@ -4230,12 +4232,13 @@ static void offline_css(struct cgroup_subsys_state *css) static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss) { struct cgroup *parent = cgroup_parent(cgrp); + struct cgroup_subsys_state *parent_css = cgroup_css(parent, ss); struct cgroup_subsys_state *css; int err; lockdep_assert_held(&cgroup_mutex); - css = ss->css_alloc(cgroup_css(parent, ss)); + css = ss->css_alloc(parent_css); if (IS_ERR(css)) return PTR_ERR(css); @@ -4255,11 +4258,12 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss) goto err_free_id; /* @css is ready to be brought online now, make it visible */ + list_add_tail_rcu(&css->sibling, &parent_css->children); cgroup_idr_replace(&ss->css_idr, css, css->id); err = online_css(css); if (err) - goto err_clear_dir; + goto err_list_del; if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && cgroup_parent(parent)) { @@ -4272,7 +4276,8 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss) return 0; -err_clear_dir: +err_list_del: + list_del_rcu(&css->sibling); cgroup_clear_dir(css->cgroup, 1 << css->ss->id); err_free_id: cgroup_idr_remove(&ss->css_idr, css->id); |