Skip to content

Commit

Permalink
Merge branch 'for-3.13-fixes' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/tj/cgroup

Pull cgroup fixes from Tejun Heo:
 "Two fixes.  One fixes a bug in the error path of cgroup_create().  The
  other changes cgrp->id lifetime rule so that the id doesn't get
  recycled before all controller states are destroyed.  This premature
  id recycling made memcg malfunction"

* 'for-3.13-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
  cgroup: don't recycle cgroup id until all csses' have been destroyed
  cgroup: fix cgroup_create() error handling path
  • Loading branch information
Linus Torvalds committed Dec 24, 2013
2 parents f639860 + c1a7150 commit 70e672f
Showing 1 changed file with 32 additions and 18 deletions.
50 changes: 32 additions & 18 deletions kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,16 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
struct cgroup *cgrp = dentry->d_fsdata;

BUG_ON(!(cgroup_is_dead(cgrp)));

/*
* XXX: cgrp->id is only used to look up css's. As cgroup
* and css's lifetimes will be decoupled, it should be made
* per-subsystem and moved to css->id so that lookups are
* successful until the target css is released.
*/
idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
cgrp->id = -1;

call_rcu(&cgrp->rcu_head, cgroup_free_rcu);
} else {
struct cfent *cfe = __d_cfe(dentry);
Expand Down Expand Up @@ -4268,6 +4278,7 @@ static void css_release(struct percpu_ref *ref)
struct cgroup_subsys_state *css =
container_of(ref, struct cgroup_subsys_state, refcnt);

rcu_assign_pointer(css->cgroup->subsys[css->ss->subsys_id], NULL);
call_rcu(&css->rcu_head, css_free_rcu_fn);
}

Expand Down Expand Up @@ -4426,14 +4437,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);

Expand All @@ -4445,6 +4448,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",
Expand Down Expand Up @@ -4491,6 +4501,14 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
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);
Expand Down Expand Up @@ -4652,8 +4670,12 @@ 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_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
Expand Down Expand Up @@ -4722,14 +4744,6 @@ static void cgroup_destroy_css_killed(struct cgroup *cgrp)
/* delete this cgroup from parent->children */
list_del_rcu(&cgrp->sibling);

/*
* We should remove the cgroup object from idr before its grace
* period starts, so we won't be looking up a cgroup while the
* cgroup is being freed.
*/
idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
cgrp->id = -1;

dput(d);

set_bit(CGRP_RELEASABLE, &parent->flags);
Expand Down

0 comments on commit 70e672f

Please sign in to comment.