mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 09:50:04 +00:00
cgroup: make cgrp_dfl_root mountable
cgrp_dfl_root will be used as the default unified hierarchy. This patch makes cgrp_dfl_root mountable by making the following changes. * cgroup_init_early() now initializes cgrp_dfl_root w/ CGRP_ROOT_SANE_BEHAVIOR. The default hierarchy is always sane. * parse_cgroupfs_options() and cgroup_mount() are updated such that cgrp_dfl_root is mounted if sane_behavior is specified w/o any subsystems. * rebind_subsystems() now populates the root directory of cgrp_dfl_root. Note that the function still guarantees success of rebinding subsystems to cgrp_dfl_root. If populating fails while rebinding to cgrp_dfl_root, it whines but ignores the error. * For backward compatibility, the default hierarchy shows up in /proc/$PID/cgroup only after it's explicitly mounted so that userland which doesn't make use of it doesn't see any change. * "current_css_set_cg_links" file of debug cgroup now treats the default hierarchy the same as other hierarchies. This is visible to userland. Given that it's for debug controller, this should be fine. * While at it, implement cgroup_on_dfl() which tests whether a give cgroup is on the default hierarchy or not. The above changes make cgrp_dfl_root mostly equivalent to other controllers but the actual unified hierarchy behaviors are not implemented yet. Let's plug child cgroup creation in cgrp_dfl_root from create_cgroup() for now. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com>
This commit is contained in:
parent
4d3bb511b5
commit
a2dd424750
2 changed files with 71 additions and 33 deletions
|
@ -250,6 +250,9 @@ enum {
|
||||||
*
|
*
|
||||||
* - "cgroup.clone_children" is removed.
|
* - "cgroup.clone_children" is removed.
|
||||||
*
|
*
|
||||||
|
* - If mount is requested with sane_behavior but without any
|
||||||
|
* subsystem, the default unified hierarchy is mounted.
|
||||||
|
*
|
||||||
* - cpuset: tasks will be kept in empty cpusets when hotplug happens
|
* - cpuset: tasks will be kept in empty cpusets when hotplug happens
|
||||||
* and take masks of ancestors with non-empty cpus/mems, instead of
|
* and take masks of ancestors with non-empty cpus/mems, instead of
|
||||||
* being moved to an ancestor.
|
* being moved to an ancestor.
|
||||||
|
@ -468,6 +471,13 @@ struct cftype {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern struct cgroup_root cgrp_dfl_root;
|
||||||
|
|
||||||
|
static inline bool cgroup_on_dfl(const struct cgroup *cgrp)
|
||||||
|
{
|
||||||
|
return cgrp->root == &cgrp_dfl_root;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See the comment above CGRP_ROOT_SANE_BEHAVIOR for details. This
|
* See the comment above CGRP_ROOT_SANE_BEHAVIOR for details. This
|
||||||
* function can be called as long as @cgrp is accessible.
|
* function can be called as long as @cgrp is accessible.
|
||||||
|
|
|
@ -142,7 +142,13 @@ static const char *cgroup_subsys_name[] = {
|
||||||
* unattached - it never has more than a single cgroup, and all tasks are
|
* unattached - it never has more than a single cgroup, and all tasks are
|
||||||
* part of that cgroup.
|
* part of that cgroup.
|
||||||
*/
|
*/
|
||||||
static struct cgroup_root cgrp_dfl_root;
|
struct cgroup_root cgrp_dfl_root;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The default hierarchy always exists but is hidden until mounted for the
|
||||||
|
* first time. This is for backward compatibility.
|
||||||
|
*/
|
||||||
|
static bool cgrp_dfl_root_visible;
|
||||||
|
|
||||||
/* The list of hierarchy roots */
|
/* The list of hierarchy roots */
|
||||||
|
|
||||||
|
@ -999,10 +1005,22 @@ static int rebind_subsystems(struct cgroup_root *dst_root,
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst_root != &cgrp_dfl_root) {
|
ret = cgroup_populate_dir(&dst_root->cgrp, ss_mask);
|
||||||
ret = cgroup_populate_dir(&dst_root->cgrp, ss_mask);
|
if (ret) {
|
||||||
if (ret)
|
if (dst_root != &cgrp_dfl_root)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rebinding back to the default root is not allowed to
|
||||||
|
* fail. Using both default and non-default roots should
|
||||||
|
* be rare. Moving subsystems back and forth even more so.
|
||||||
|
* Just warn about it and continue.
|
||||||
|
*/
|
||||||
|
if (cgrp_dfl_root_visible) {
|
||||||
|
pr_warning("cgroup: failed to create files (%d) while rebinding 0x%lx to default root\n",
|
||||||
|
ret, ss_mask);
|
||||||
|
pr_warning("cgroup: you may retry by moving them to a different hierarchy and unbinding\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1011,7 +1029,7 @@ static int rebind_subsystems(struct cgroup_root *dst_root,
|
||||||
*/
|
*/
|
||||||
mutex_unlock(&cgroup_mutex);
|
mutex_unlock(&cgroup_mutex);
|
||||||
for_each_subsys(ss, ssid)
|
for_each_subsys(ss, ssid)
|
||||||
if ((ss_mask & (1 << ssid)) && ss->root != &cgrp_dfl_root)
|
if (ss_mask & (1 << ssid))
|
||||||
cgroup_clear_dir(&ss->root->cgrp, 1 << ssid);
|
cgroup_clear_dir(&ss->root->cgrp, 1 << ssid);
|
||||||
mutex_lock(&cgroup_mutex);
|
mutex_lock(&cgroup_mutex);
|
||||||
|
|
||||||
|
@ -1039,8 +1057,7 @@ static int rebind_subsystems(struct cgroup_root *dst_root,
|
||||||
ss->bind(css);
|
ss->bind(css);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst_root != &cgrp_dfl_root)
|
kernfs_activate(dst_root->cgrp.kn);
|
||||||
kernfs_activate(dst_root->cgrp.kn);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,16 +1207,6 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If the 'all' option was specified select all the subsystems,
|
|
||||||
* otherwise if 'none', 'name=' and a subsystem name options
|
|
||||||
* were not specified, let's default to 'all'
|
|
||||||
*/
|
|
||||||
if (all_ss || (!one_ss && !opts->none && !opts->name))
|
|
||||||
for_each_subsys(ss, i)
|
|
||||||
if (!ss->disabled)
|
|
||||||
set_bit(i, &opts->subsys_mask);
|
|
||||||
|
|
||||||
/* Consistency checks */
|
/* Consistency checks */
|
||||||
|
|
||||||
if (opts->flags & CGRP_ROOT_SANE_BEHAVIOR) {
|
if (opts->flags & CGRP_ROOT_SANE_BEHAVIOR) {
|
||||||
|
@ -1211,6 +1218,23 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
|
||||||
pr_err("cgroup: sane_behavior: noprefix, xattr, clone_children, release_agent and name are not allowed\n");
|
pr_err("cgroup: sane_behavior: noprefix, xattr, clone_children, release_agent and name are not allowed\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If the 'all' option was specified select all the
|
||||||
|
* subsystems, otherwise if 'none', 'name=' and a subsystem
|
||||||
|
* name options were not specified, let's default to 'all'
|
||||||
|
*/
|
||||||
|
if (all_ss || (!one_ss && !opts->none && !opts->name))
|
||||||
|
for_each_subsys(ss, i)
|
||||||
|
if (!ss->disabled)
|
||||||
|
set_bit(i, &opts->subsys_mask);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We either have to specify by name or by subsystems. (So
|
||||||
|
* all empty hierarchies must have a name).
|
||||||
|
*/
|
||||||
|
if (!opts->subsys_mask && !opts->name)
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1226,13 +1250,6 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
|
||||||
if (opts->subsys_mask && opts->none)
|
if (opts->subsys_mask && opts->none)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
|
||||||
* We either have to specify by name or by subsystems. (So all
|
|
||||||
* empty hierarchies must have a name).
|
|
||||||
*/
|
|
||||||
if (!opts->subsys_mask && !opts->name)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1487,6 +1504,14 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
/* look for a matching existing root */
|
/* look for a matching existing root */
|
||||||
|
if (!opts.subsys_mask && !opts.none && !opts.name) {
|
||||||
|
cgrp_dfl_root_visible = true;
|
||||||
|
root = &cgrp_dfl_root;
|
||||||
|
cgroup_get(&root->cgrp);
|
||||||
|
ret = 0;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
for_each_root(root) {
|
for_each_root(root) {
|
||||||
bool name_match = false;
|
bool name_match = false;
|
||||||
|
|
||||||
|
@ -3622,6 +3647,13 @@ static long cgroup_create(struct cgroup *parent, const char *name,
|
||||||
struct cgroup_subsys *ss;
|
struct cgroup_subsys *ss;
|
||||||
struct kernfs_node *kn;
|
struct kernfs_node *kn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: The default hierarchy isn't fully implemented yet. Block
|
||||||
|
* !root cgroup creation on it for now.
|
||||||
|
*/
|
||||||
|
if (root == &cgrp_dfl_root)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* allocate the cgroup and its ID, 0 is reserved for the root */
|
/* allocate the cgroup and its ID, 0 is reserved for the root */
|
||||||
cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);
|
cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);
|
||||||
if (!cgrp)
|
if (!cgrp)
|
||||||
|
@ -4061,7 +4093,8 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
|
||||||
*/
|
*/
|
||||||
int __init cgroup_init_early(void)
|
int __init cgroup_init_early(void)
|
||||||
{
|
{
|
||||||
static struct cgroup_sb_opts __initdata opts = { };
|
static struct cgroup_sb_opts __initdata opts =
|
||||||
|
{ .flags = CGRP_ROOT_SANE_BEHAVIOR };
|
||||||
struct cgroup_subsys *ss;
|
struct cgroup_subsys *ss;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -4198,7 +4231,7 @@ int proc_cgroup_show(struct seq_file *m, void *v)
|
||||||
struct cgroup *cgrp;
|
struct cgroup *cgrp;
|
||||||
int ssid, count = 0;
|
int ssid, count = 0;
|
||||||
|
|
||||||
if (root == &cgrp_dfl_root)
|
if (root == &cgrp_dfl_root && !cgrp_dfl_root_visible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
seq_printf(m, "%d:", root->hierarchy_id);
|
seq_printf(m, "%d:", root->hierarchy_id);
|
||||||
|
@ -4631,15 +4664,10 @@ static int current_css_set_cg_links_read(struct seq_file *seq, void *v)
|
||||||
cset = rcu_dereference(current->cgroups);
|
cset = rcu_dereference(current->cgroups);
|
||||||
list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
|
list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
|
||||||
struct cgroup *c = link->cgrp;
|
struct cgroup *c = link->cgrp;
|
||||||
const char *name = "?";
|
|
||||||
|
|
||||||
if (c != &cgrp_dfl_root.cgrp) {
|
|
||||||
cgroup_name(c, name_buf, NAME_MAX + 1);
|
|
||||||
name = name_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cgroup_name(c, name_buf, NAME_MAX + 1);
|
||||||
seq_printf(seq, "Root %d group %s\n",
|
seq_printf(seq, "Root %d group %s\n",
|
||||||
c->root->hierarchy_id, name);
|
c->root->hierarchy_id, name_buf);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
up_read(&css_set_rwsem);
|
up_read(&css_set_rwsem);
|
||||||
|
|
Loading…
Reference in a new issue