summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-02-11 17:02:59 +0100
committerTejun Heo <tj@kernel.org>2014-02-11 17:02:59 +0100
commit398f878789fceb51bf5e424b753a3756643513c4 (patch)
treecd80a446bd1e2f1adc5652a805ac2f98a40b003e
parentMerge branch 'driver-core-next' into cgroup/for-3.15 (diff)
parentcgroup: protect modifications to cgroup_idr with cgroup_mutex (diff)
downloadlinux-398f878789fceb51bf5e424b753a3756643513c4.tar.xz
linux-398f878789fceb51bf5e424b753a3756643513c4.zip
Merge branch 'cgroup/for-3.14-fixes' into cgroup/for-3.15
Pull for-3.14-fixes to receive 0ab02ca8f887 ("cgroup: protect modifications to cgroup_idr with cgroup_mutex") prior to kernfs conversion series to avoid non-trivial conflicts. Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--include/linux/cgroup.h2
-rw-r--r--kernel/cgroup.c34
2 files changed, 20 insertions, 16 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 198c7fcd727e..c86ba7ff7a7e 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -151,6 +151,8 @@ struct cgroup {
*
* The ID of the root cgroup is always 0, and a new cgroup
* will be assigned with a smallest available ID.
+ *
+ * Allocating/Removing ID must be protected by cgroup_mutex.
*/
int id;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index f5bbe5885364..2de8decfd99f 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -850,7 +850,9 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
* per-subsystem and moved to css->id so that lookups are
* successful until the target css is released.
*/
+ mutex_lock(&cgroup_mutex);
idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
+ mutex_unlock(&cgroup_mutex);
cgrp->id = -1;
call_rcu(&cgrp->rcu_head, cgroup_free_rcu);
@@ -4092,16 +4094,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
rcu_assign_pointer(cgrp->name, name);
/*
- * Temporarily set the pointer to NULL, so idr_find() won't return
- * a half-baked cgroup.
- */
- cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
- if (cgrp->id < 0) {
- err = -ENOMEM;
- goto err_free_name;
- }
-
- /*
* Only live parents can have children. Note that the liveliness
* check isn't strictly necessary because cgroup_mkdir() and
* cgroup_rmdir() are fully synchronized by i_mutex; however, do it
@@ -4110,7 +4102,17 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
*/
if (!cgroup_lock_live_group(parent)) {
err = -ENODEV;
- goto err_free_id;
+ goto err_free_name;
+ }
+
+ /*
+ * Temporarily set the pointer to NULL, so idr_find() won't return
+ * a half-baked cgroup.
+ */
+ cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
+ if (cgrp->id < 0) {
+ err = -ENOMEM;
+ goto err_unlock;
}
/* Grab a reference on the superblock so the hierarchy doesn't
@@ -4142,7 +4144,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
*/
err = cgroup_create_file(dentry, S_IFDIR | mode, sb);
if (err < 0)
- goto err_unlock;
+ goto err_free_id;
lockdep_assert_held(&dentry->d_inode->i_mutex);
cgrp->serial_nr = cgroup_serial_nr_next++;
@@ -4178,12 +4180,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
return 0;
-err_unlock:
- mutex_unlock(&cgroup_mutex);
- /* Release the reference count that we took on the superblock */
- deactivate_super(sb);
err_free_id:
idr_remove(&root->cgroup_idr, cgrp->id);
+ /* Release the reference count that we took on the superblock */
+ deactivate_super(sb);
+err_unlock:
+ mutex_unlock(&cgroup_mutex);
err_free_name:
kfree(rcu_dereference_raw(cgrp->name));
err_free_cgrp: