cgroup: factor out cgroup_setup_root() from cgroup_mount()
Factor out new root initialization into cgroup_setup_root() from cgroup_mount(). This makes it easier to follow and will ease kernfs conversion. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com>
This commit is contained in:
parent
8e30e2b8ba
commit
d427dfeb12
1 changed files with 113 additions and 98 deletions
211
kernel/cgroup.c
211
kernel/cgroup.c
|
@ -1455,17 +1455,126 @@ static int cgroup_get_rootdir(struct super_block *sb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cgroup_setup_root(struct cgroupfs_root *root)
|
||||||
|
{
|
||||||
|
LIST_HEAD(tmp_links);
|
||||||
|
struct super_block *sb = root->sb;
|
||||||
|
struct cgroup *root_cgrp = &root->top_cgroup;
|
||||||
|
struct cgroupfs_root *existing_root;
|
||||||
|
struct css_set *cset;
|
||||||
|
struct inode *inode;
|
||||||
|
const struct cred *cred;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
lockdep_assert_held(&cgroup_tree_mutex);
|
||||||
|
lockdep_assert_held(&cgroup_mutex);
|
||||||
|
BUG_ON(sb->s_root != NULL);
|
||||||
|
|
||||||
|
mutex_unlock(&cgroup_mutex);
|
||||||
|
mutex_unlock(&cgroup_tree_mutex);
|
||||||
|
|
||||||
|
ret = cgroup_get_rootdir(sb);
|
||||||
|
if (ret) {
|
||||||
|
mutex_lock(&cgroup_tree_mutex);
|
||||||
|
mutex_lock(&cgroup_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
inode = sb->s_root->d_inode;
|
||||||
|
|
||||||
|
mutex_lock(&inode->i_mutex);
|
||||||
|
mutex_lock(&cgroup_tree_mutex);
|
||||||
|
mutex_lock(&cgroup_mutex);
|
||||||
|
|
||||||
|
ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_unlock;
|
||||||
|
root_cgrp->id = ret;
|
||||||
|
|
||||||
|
/* check for name clashes with existing mounts */
|
||||||
|
ret = -EBUSY;
|
||||||
|
if (strlen(root->name))
|
||||||
|
for_each_active_root(existing_root)
|
||||||
|
if (!strcmp(existing_root->name, root->name))
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We're accessing css_set_count without locking css_set_lock here,
|
||||||
|
* but that's OK - it can only be increased by someone holding
|
||||||
|
* cgroup_lock, and that's us. The worst that can happen is that we
|
||||||
|
* have some link structures left over
|
||||||
|
*/
|
||||||
|
ret = allocate_cgrp_cset_links(css_set_count, &tmp_links);
|
||||||
|
if (ret)
|
||||||
|
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 out_unlock;
|
||||||
|
|
||||||
|
sb->s_root->d_fsdata = root_cgrp;
|
||||||
|
root_cgrp->dentry = sb->s_root;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We're inside get_sb() and will call lookup_one_len() to create
|
||||||
|
* the root files, which doesn't work if SELinux is in use. The
|
||||||
|
* following cred dancing somehow works around it. See 2ce9738ba
|
||||||
|
* ("cgroupfs: use init_cred when populating new cgroupfs mount")
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
cred = override_creds(&init_cred);
|
||||||
|
|
||||||
|
ret = cgroup_addrm_files(root_cgrp, cgroup_base_files, true);
|
||||||
|
if (ret)
|
||||||
|
goto rm_base_files;
|
||||||
|
|
||||||
|
ret = rebind_subsystems(root, root->subsys_mask, 0);
|
||||||
|
if (ret)
|
||||||
|
goto rm_base_files;
|
||||||
|
|
||||||
|
revert_creds(cred);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There must be no failure case after here, since rebinding takes
|
||||||
|
* care of subsystems' refcounts, which are explicitly dropped in
|
||||||
|
* the failure exit path.
|
||||||
|
*/
|
||||||
|
list_add(&root->root_list, &cgroup_roots);
|
||||||
|
cgroup_root_count++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Link the top cgroup in this hierarchy into all the css_set
|
||||||
|
* objects.
|
||||||
|
*/
|
||||||
|
write_lock(&css_set_lock);
|
||||||
|
hash_for_each(css_set_table, i, cset, hlist)
|
||||||
|
link_css_set(&tmp_links, cset, root_cgrp);
|
||||||
|
write_unlock(&css_set_lock);
|
||||||
|
|
||||||
|
BUG_ON(!list_empty(&root_cgrp->children));
|
||||||
|
BUG_ON(root->number_of_cgroups != 1);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
rm_base_files:
|
||||||
|
cgroup_addrm_files(&root->top_cgroup, cgroup_base_files, false);
|
||||||
|
revert_creds(cred);
|
||||||
|
cgroup_exit_root_id(root);
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
free_cgrp_cset_links(&tmp_links);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dentry *cgroup_mount(struct file_system_type *fs_type,
|
static struct dentry *cgroup_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *unused_dev_name,
|
int flags, const char *unused_dev_name,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
LIST_HEAD(tmp_links);
|
|
||||||
struct super_block *sb = NULL;
|
struct super_block *sb = NULL;
|
||||||
struct inode *inode = NULL;
|
|
||||||
struct cgroupfs_root *root = NULL;
|
struct cgroupfs_root *root = NULL;
|
||||||
struct cgroup_sb_opts opts;
|
struct cgroup_sb_opts opts;
|
||||||
struct cgroupfs_root *new_root;
|
struct cgroupfs_root *new_root;
|
||||||
const struct cred *cred;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&cgroup_tree_mutex);
|
mutex_lock(&cgroup_tree_mutex);
|
||||||
|
@ -1502,94 +1611,9 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
|
||||||
root = sb->s_fs_info;
|
root = sb->s_fs_info;
|
||||||
BUG_ON(!root);
|
BUG_ON(!root);
|
||||||
if (root == opts.new_root) {
|
if (root == opts.new_root) {
|
||||||
/* We used the new root structure, so this is a new hierarchy */
|
ret = cgroup_setup_root(root);
|
||||||
struct cgroup *root_cgrp = &root->top_cgroup;
|
|
||||||
struct cgroupfs_root *existing_root;
|
|
||||||
int i;
|
|
||||||
struct css_set *cset;
|
|
||||||
|
|
||||||
BUG_ON(sb->s_root != NULL);
|
|
||||||
|
|
||||||
mutex_unlock(&cgroup_mutex);
|
|
||||||
mutex_unlock(&cgroup_tree_mutex);
|
|
||||||
|
|
||||||
ret = cgroup_get_rootdir(sb);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
inode = sb->s_root->d_inode;
|
|
||||||
|
|
||||||
mutex_lock(&inode->i_mutex);
|
|
||||||
mutex_lock(&cgroup_tree_mutex);
|
|
||||||
mutex_lock(&cgroup_mutex);
|
|
||||||
|
|
||||||
ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out_unlock;
|
|
||||||
root_cgrp->id = ret;
|
|
||||||
|
|
||||||
/* Check for name clashes with existing mounts */
|
|
||||||
ret = -EBUSY;
|
|
||||||
if (strlen(root->name))
|
|
||||||
for_each_active_root(existing_root)
|
|
||||||
if (!strcmp(existing_root->name, root->name))
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We're accessing css_set_count without locking
|
|
||||||
* css_set_lock here, but that's OK - it can only be
|
|
||||||
* increased by someone holding cgroup_lock, and
|
|
||||||
* that's us. The worst that can happen is that we
|
|
||||||
* have some link structures left over
|
|
||||||
*/
|
|
||||||
ret = allocate_cgrp_cset_links(css_set_count, &tmp_links);
|
|
||||||
if (ret)
|
|
||||||
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 out_unlock;
|
|
||||||
|
|
||||||
sb->s_root->d_fsdata = root_cgrp;
|
|
||||||
root_cgrp->dentry = sb->s_root;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We're inside get_sb() and will call lookup_one_len() to
|
|
||||||
* create the root files, which doesn't work if SELinux is
|
|
||||||
* in use. The following cred dancing somehow works around
|
|
||||||
* it. See 2ce9738ba ("cgroupfs: use init_cred when
|
|
||||||
* populating new cgroupfs mount") for more details.
|
|
||||||
*/
|
|
||||||
cred = override_creds(&init_cred);
|
|
||||||
|
|
||||||
ret = cgroup_addrm_files(root_cgrp, cgroup_base_files, true);
|
|
||||||
if (ret)
|
|
||||||
goto rm_base_files;
|
|
||||||
|
|
||||||
ret = rebind_subsystems(root, root->subsys_mask, 0);
|
|
||||||
if (ret)
|
|
||||||
goto rm_base_files;
|
|
||||||
|
|
||||||
revert_creds(cred);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There must be no failure case after here, since rebinding
|
|
||||||
* takes care of subsystems' refcounts, which are explicitly
|
|
||||||
* dropped in the failure exit path.
|
|
||||||
*/
|
|
||||||
|
|
||||||
list_add(&root->root_list, &cgroup_roots);
|
|
||||||
cgroup_root_count++;
|
|
||||||
|
|
||||||
/* Link the top cgroup in this hierarchy into all
|
|
||||||
* the css_set objects */
|
|
||||||
write_lock(&css_set_lock);
|
|
||||||
hash_for_each(css_set_table, i, cset, hlist)
|
|
||||||
link_css_set(&tmp_links, cset, root_cgrp);
|
|
||||||
write_unlock(&css_set_lock);
|
|
||||||
|
|
||||||
BUG_ON(!list_empty(&root_cgrp->children));
|
|
||||||
BUG_ON(root->number_of_cgroups != 1);
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* We re-used an existing hierarchy - the new root (if
|
* We re-used an existing hierarchy - the new root (if
|
||||||
|
@ -1609,22 +1633,13 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
rm_base_files:
|
|
||||||
cgroup_addrm_files(&root->top_cgroup, cgroup_base_files, false);
|
|
||||||
revert_creds(cred);
|
|
||||||
cgroup_exit_root_id(root);
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&cgroup_mutex);
|
mutex_unlock(&cgroup_mutex);
|
||||||
mutex_unlock(&cgroup_tree_mutex);
|
mutex_unlock(&cgroup_tree_mutex);
|
||||||
if (inode)
|
|
||||||
mutex_unlock(&inode->i_mutex);
|
|
||||||
|
|
||||||
if (ret && !IS_ERR_OR_NULL(sb))
|
if (ret && !IS_ERR_OR_NULL(sb))
|
||||||
deactivate_locked_super(sb);
|
deactivate_locked_super(sb);
|
||||||
|
|
||||||
free_cgrp_cset_links(&tmp_links);
|
|
||||||
kfree(opts.release_agent);
|
kfree(opts.release_agent);
|
||||||
kfree(opts.name);
|
kfree(opts.name);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue