summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/cgroup.c73
1 files changed, 40 insertions, 33 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index d28cf75f33c1..083b53d79d6f 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1459,21 +1459,22 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
int flags, const char *unused_dev_name,
void *data)
{
+ LIST_HEAD(tmp_links);
+ struct super_block *sb = NULL;
+ struct inode *inode = NULL;
+ struct cgroupfs_root *root = NULL;
struct cgroup_sb_opts opts;
- struct cgroupfs_root *root;
- int ret = 0;
- struct super_block *sb;
struct cgroupfs_root *new_root;
- struct list_head tmp_links;
- struct inode *inode;
const struct cred *cred;
+ int ret;
- /* First find the desired set of subsystems */
+ mutex_lock(&cgroup_tree_mutex);
mutex_lock(&cgroup_mutex);
+
+ /* First find the desired set of subsystems */
ret = parse_cgroupfs_options(data, &opts);
- mutex_unlock(&cgroup_mutex);
if (ret)
- goto out_err;
+ goto out_unlock;
/*
* Allocate a new cgroup root. We may not need it if we're
@@ -1482,16 +1483,20 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
new_root = cgroup_root_from_opts(&opts);
if (IS_ERR(new_root)) {
ret = PTR_ERR(new_root);
- goto out_err;
+ goto out_unlock;
}
opts.new_root = new_root;
/* Locate an existing or new sb for this hierarchy */
+ mutex_unlock(&cgroup_mutex);
+ mutex_unlock(&cgroup_tree_mutex);
sb = sget(fs_type, cgroup_test_super, cgroup_set_super, 0, &opts);
+ mutex_lock(&cgroup_tree_mutex);
+ mutex_lock(&cgroup_mutex);
if (IS_ERR(sb)) {
ret = PTR_ERR(sb);
cgroup_free_root(opts.new_root);
- goto out_err;
+ goto out_unlock;
}
root = sb->s_fs_info;
@@ -1505,9 +1510,12 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
BUG_ON(sb->s_root != NULL);
+ mutex_unlock(&cgroup_mutex);
+ mutex_unlock(&cgroup_tree_mutex);
+
ret = cgroup_get_rootdir(sb);
if (ret)
- goto drop_new_super;
+ goto out_unlock;
inode = sb->s_root->d_inode;
mutex_lock(&inode->i_mutex);
@@ -1516,7 +1524,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL);
if (ret < 0)
- goto unlock_drop;
+ goto out_unlock;
root_cgrp->id = ret;
/* Check for name clashes with existing mounts */
@@ -1524,7 +1532,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
if (strlen(root->name))
for_each_active_root(existing_root)
if (!strcmp(existing_root->name, root->name))
- goto unlock_drop;
+ goto out_unlock;
/*
* We're accessing css_set_count without locking
@@ -1535,12 +1543,12 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
*/
ret = allocate_cgrp_cset_links(css_set_count, &tmp_links);
if (ret)
- goto unlock_drop;
+ goto out_unlock;
/* ID 0 is reserved for dummy root, 1 for unified hierarchy */
ret = cgroup_init_root_id(root, 2, 0);
if (ret)
- goto unlock_drop;
+ goto out_unlock;
sb->s_root->d_fsdata = root_cgrp;
root_cgrp->dentry = sb->s_root;
@@ -1580,14 +1588,8 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
link_css_set(&tmp_links, cset, root_cgrp);
write_unlock(&css_set_lock);
- free_cgrp_cset_links(&tmp_links);
-
BUG_ON(!list_empty(&root_cgrp->children));
BUG_ON(root->number_of_cgroups != 1);
-
- mutex_unlock(&cgroup_mutex);
- mutex_unlock(&cgroup_tree_mutex);
- mutex_unlock(&inode->i_mutex);
} else {
/*
* We re-used an existing hierarchy - the new root (if
@@ -1599,32 +1601,37 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
if ((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) {
pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n");
ret = -EINVAL;
- goto drop_new_super;
+ goto out_unlock;
} else {
pr_warning("cgroup: new mount options do not match the existing superblock, will be ignored\n");
}
}
}
- kfree(opts.release_agent);
- kfree(opts.name);
- return dget(sb->s_root);
+ ret = 0;
+ goto out_unlock;
- rm_base_files:
- free_cgrp_cset_links(&tmp_links);
+rm_base_files:
cgroup_addrm_files(&root->top_cgroup, cgroup_base_files, false);
revert_creds(cred);
- unlock_drop:
cgroup_exit_root_id(root);
+out_unlock:
mutex_unlock(&cgroup_mutex);
mutex_unlock(&cgroup_tree_mutex);
- mutex_unlock(&inode->i_mutex);
- drop_new_super:
- deactivate_locked_super(sb);
- out_err:
+ if (inode)
+ mutex_unlock(&inode->i_mutex);
+
+ if (ret && !IS_ERR_OR_NULL(sb))
+ deactivate_locked_super(sb);
+
+ free_cgrp_cset_links(&tmp_links);
kfree(opts.release_agent);
kfree(opts.name);
- return ERR_PTR(ret);
+
+ if (!ret)
+ return dget(sb->s_root);
+ else
+ return ERR_PTR(ret);
}
static void cgroup_kill_sb(struct super_block *sb)