diff options
| -rw-r--r-- | include/linux/cgroup.h | 2 | ||||
| -rw-r--r-- | kernel/cgroup.c | 34 |
2 files changed, 20 insertions, 16 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 5c097596104b..9450f025fe0c 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
| @@ -166,6 +166,8 @@ struct cgroup { | |||
| 166 | * | 166 | * |
| 167 | * The ID of the root cgroup is always 0, and a new cgroup | 167 | * The ID of the root cgroup is always 0, and a new cgroup |
| 168 | * will be assigned with a smallest available ID. | 168 | * will be assigned with a smallest available ID. |
| 169 | * | ||
| 170 | * Allocating/Removing ID must be protected by cgroup_mutex. | ||
| 169 | */ | 171 | */ |
| 170 | int id; | 172 | int id; |
| 171 | 173 | ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 3edf7163b84f..52719ce55dd3 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -886,7 +886,9 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) | |||
| 886 | * per-subsystem and moved to css->id so that lookups are | 886 | * per-subsystem and moved to css->id so that lookups are |
| 887 | * successful until the target css is released. | 887 | * successful until the target css is released. |
| 888 | */ | 888 | */ |
| 889 | mutex_lock(&cgroup_mutex); | ||
| 889 | idr_remove(&cgrp->root->cgroup_idr, cgrp->id); | 890 | idr_remove(&cgrp->root->cgroup_idr, cgrp->id); |
| 891 | mutex_unlock(&cgroup_mutex); | ||
| 890 | cgrp->id = -1; | 892 | cgrp->id = -1; |
| 891 | 893 | ||
| 892 | call_rcu(&cgrp->rcu_head, cgroup_free_rcu); | 894 | call_rcu(&cgrp->rcu_head, cgroup_free_rcu); |
| @@ -4168,16 +4170,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
| 4168 | rcu_assign_pointer(cgrp->name, name); | 4170 | rcu_assign_pointer(cgrp->name, name); |
| 4169 | 4171 | ||
| 4170 | /* | 4172 | /* |
| 4171 | * Temporarily set the pointer to NULL, so idr_find() won't return | ||
| 4172 | * a half-baked cgroup. | ||
| 4173 | */ | ||
| 4174 | cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); | ||
| 4175 | if (cgrp->id < 0) { | ||
| 4176 | err = -ENOMEM; | ||
| 4177 | goto err_free_name; | ||
| 4178 | } | ||
| 4179 | |||
| 4180 | /* | ||
| 4181 | * Only live parents can have children. Note that the liveliness | 4173 | * Only live parents can have children. Note that the liveliness |
| 4182 | * check isn't strictly necessary because cgroup_mkdir() and | 4174 | * check isn't strictly necessary because cgroup_mkdir() and |
| 4183 | * cgroup_rmdir() are fully synchronized by i_mutex; however, do it | 4175 | * cgroup_rmdir() are fully synchronized by i_mutex; however, do it |
| @@ -4186,7 +4178,17 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
| 4186 | */ | 4178 | */ |
| 4187 | if (!cgroup_lock_live_group(parent)) { | 4179 | if (!cgroup_lock_live_group(parent)) { |
| 4188 | err = -ENODEV; | 4180 | err = -ENODEV; |
| 4189 | goto err_free_id; | 4181 | goto err_free_name; |
| 4182 | } | ||
| 4183 | |||
| 4184 | /* | ||
| 4185 | * Temporarily set the pointer to NULL, so idr_find() won't return | ||
| 4186 | * a half-baked cgroup. | ||
| 4187 | */ | ||
| 4188 | cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); | ||
| 4189 | if (cgrp->id < 0) { | ||
| 4190 | err = -ENOMEM; | ||
| 4191 | goto err_unlock; | ||
| 4190 | } | 4192 | } |
| 4191 | 4193 | ||
| 4192 | /* Grab a reference on the superblock so the hierarchy doesn't | 4194 | /* Grab a reference on the superblock so the hierarchy doesn't |
| @@ -4218,7 +4220,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
| 4218 | */ | 4220 | */ |
| 4219 | err = cgroup_create_file(dentry, S_IFDIR | mode, sb); | 4221 | err = cgroup_create_file(dentry, S_IFDIR | mode, sb); |
| 4220 | if (err < 0) | 4222 | if (err < 0) |
| 4221 | goto err_unlock; | 4223 | goto err_free_id; |
| 4222 | lockdep_assert_held(&dentry->d_inode->i_mutex); | 4224 | lockdep_assert_held(&dentry->d_inode->i_mutex); |
| 4223 | 4225 | ||
| 4224 | cgrp->serial_nr = cgroup_serial_nr_next++; | 4226 | cgrp->serial_nr = cgroup_serial_nr_next++; |
| @@ -4254,12 +4256,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
| 4254 | 4256 | ||
| 4255 | return 0; | 4257 | return 0; |
| 4256 | 4258 | ||
| 4257 | err_unlock: | ||
| 4258 | mutex_unlock(&cgroup_mutex); | ||
| 4259 | /* Release the reference count that we took on the superblock */ | ||
| 4260 | deactivate_super(sb); | ||
| 4261 | err_free_id: | 4259 | err_free_id: |
| 4262 | idr_remove(&root->cgroup_idr, cgrp->id); | 4260 | idr_remove(&root->cgroup_idr, cgrp->id); |
| 4261 | /* Release the reference count that we took on the superblock */ | ||
| 4262 | deactivate_super(sb); | ||
| 4263 | err_unlock: | ||
| 4264 | mutex_unlock(&cgroup_mutex); | ||
| 4263 | err_free_name: | 4265 | err_free_name: |
| 4264 | kfree(rcu_dereference_raw(cgrp->name)); | 4266 | kfree(rcu_dereference_raw(cgrp->name)); |
| 4265 | err_free_cgrp: | 4267 | err_free_cgrp: |
