summaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2016-03-08 11:51:26 -0500
committerTejun Heo <tj@kernel.org>2016-03-08 11:51:26 -0500
commitf6d635ad341d5cc0b9c7ab46adfbf3bf5886cee4 (patch)
tree0dc1bbf73f89b562748e1e2e57ca2262e9903b5e /kernel/cgroup.c
parente4857982f49d21c05a84351b56724bf353022355 (diff)
downloadlinux-stable-f6d635ad341d5cc0b9c7ab46adfbf3bf5886cee4.tar.gz
linux-stable-f6d635ad341d5cc0b9c7ab46adfbf3bf5886cee4.tar.bz2
linux-stable-f6d635ad341d5cc0b9c7ab46adfbf3bf5886cee4.zip
cgroup: implement cgroup_subsys->implicit_on_dfl
Some controllers, perf_event for now and possibly freezer in the future, don't really make sense to control explicitly through "cgroup.subtree_control". For example, the primary role of perf_event is identifying the cgroups of tasks; however, because the controller also keeps a small amount of state per cgroup, it can't be replaced with simple cgroup membership tests. This patch implements cgroup_subsys->implicit_on_dfl flag. When set, the controller is implicitly enabled on all cgroups on the v2 hierarchy so that utility type controllers such as perf_event can be enabled and function transparently. An implicit controller doesn't show up in "cgroup.controllers" or "cgroup.subtree_control", is exempt from no internal process rule and can be stolen from the default hierarchy even if there are non-root csses. v2: Reimplemented on top of the recent updates to css handling and subsystem rebinding. Rebinding implicit subsystems is now a simple matter of exempting it from the busy subsystem check. Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index fbd3e99a4e98..e22df5d81e59 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -186,6 +186,9 @@ static u16 cgroup_no_v1_mask;
/* some controllers are not supported in the default hierarchy */
static u16 cgrp_dfl_inhibit_ss_mask;
+/* some controllers are implicitly enabled on the default hierarchy */
+static unsigned long cgrp_dfl_implicit_ss_mask;
+
/* The list of hierarchy roots */
static LIST_HEAD(cgroup_roots);
@@ -359,8 +362,8 @@ static u16 cgroup_control(struct cgroup *cgrp)
return parent->subtree_control;
if (cgroup_on_dfl(cgrp))
- root_ss_mask &= ~cgrp_dfl_inhibit_ss_mask;
-
+ root_ss_mask &= ~(cgrp_dfl_inhibit_ss_mask |
+ cgrp_dfl_implicit_ss_mask);
return root_ss_mask;
}
@@ -1327,6 +1330,8 @@ static u16 cgroup_calc_subtree_ss_mask(u16 subtree_control, u16 this_ss_mask)
lockdep_assert_held(&cgroup_mutex);
+ cur_ss_mask |= cgrp_dfl_implicit_ss_mask;
+
while (true) {
u16 new_ss_mask = cur_ss_mask;
@@ -1512,8 +1517,13 @@ static int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
lockdep_assert_held(&cgroup_mutex);
do_each_subsys_mask(ss, ssid, ss_mask) {
- /* if @ss has non-root csses attached to it, can't move */
- if (css_next_child(NULL, cgroup_css(&ss->root->cgrp, ss)))
+ /*
+ * If @ss has non-root csses attached to it, can't move.
+ * If @ss is an implicit controller, it is exempt from this
+ * rule and can be stolen.
+ */
+ if (css_next_child(NULL, cgroup_css(&ss->root->cgrp, ss)) &&
+ !ss->implicit_on_dfl)
return -EBUSY;
/* can't move between two non-dummy roots either */
@@ -3039,6 +3049,18 @@ static void cgroup_restore_control(struct cgroup *cgrp)
}
}
+static bool css_visible(struct cgroup_subsys_state *css)
+{
+ struct cgroup_subsys *ss = css->ss;
+ struct cgroup *cgrp = css->cgroup;
+
+ if (cgroup_control(cgrp) & (1 << ss->id))
+ return true;
+ if (!(cgroup_ss_mask(cgrp) & (1 << ss->id)))
+ return false;
+ return cgroup_on_dfl(cgrp) && ss->implicit_on_dfl;
+}
+
/**
* cgroup_apply_control_enable - enable or show csses according to control
* @cgrp: root of the target subtree
@@ -3074,7 +3096,7 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp)
return PTR_ERR(css);
}
- if (cgroup_control(dsct) & (1 << ss->id)) {
+ if (css_visible(css)) {
ret = css_populate_dir(css);
if (ret)
return ret;
@@ -3117,7 +3139,7 @@ static void cgroup_apply_control_disable(struct cgroup *cgrp)
if (css->parent &&
!(cgroup_ss_mask(dsct) & (1 << ss->id))) {
kill_css(css);
- } else if (!(cgroup_control(dsct) & (1 << ss->id))) {
+ } else if (!css_visible(css)) {
css_clear_dir(css);
if (ss->css_reset)
ss->css_reset(css);
@@ -5455,7 +5477,9 @@ int __init cgroup_init(void)
cgrp_dfl_root.subsys_mask |= 1 << ss->id;
- if (!ss->dfl_cftypes)
+ if (ss->implicit_on_dfl)
+ cgrp_dfl_implicit_ss_mask |= 1 << ss->id;
+ else if (!ss->dfl_cftypes)
cgrp_dfl_inhibit_ss_mask |= 1 << ss->id;
if (ss->dfl_cftypes == ss->legacy_cftypes) {