cgroupfs_root->subsys_mask represents the controllers attached to the
hierarchy. This patch moves the field to cgroup. Subsystem
initialization and rebinding updates the top cgroup's subsys_mask.
For !root cgroups, the subsys_mask bits are set from create_css() and
cleared from kill_css(), which effectively means that all cgroups will
have the same subsys_mask as the top cgroup.
While this doesn't make any difference now, this will help
implementation of the default unified hierarchy where !root cgroups
may have subsets of the top_cgroup's subsys_mask.
While at it, __kill_css() is split out of kill_css(). The former
doesn't care about the subsys_mask while the latter becomes noop if
the controller is already killed and clears the matching bit if not
before proceeding to killing the css. This will be used later by the
default unified hierarchy implementation.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
+ /* The bitmask of subsystems attached to this cgroup */
+ unsigned long subsys_mask;
+
/* Private pointers for each registered subsystem */
struct cgroup_subsys_state __rcu *subsys[CGROUP_SUBSYS_COUNT];
/* Private pointers for each registered subsystem */
struct cgroup_subsys_state __rcu *subsys[CGROUP_SUBSYS_COUNT];
struct cgroupfs_root {
struct kernfs_root *kf_root;
struct cgroupfs_root {
struct kernfs_root *kf_root;
- /* The bitmask of subsystems attached to this hierarchy */
- unsigned long subsys_mask;
-
/* Unique id for this hierarchy. */
int hierarchy_id;
/* Unique id for this hierarchy. */
int hierarchy_id;
* won't change, so no need for locking.
*/
for_each_subsys(ss, i) {
* won't change, so no need for locking.
*/
for_each_subsys(ss, i) {
- if (root->subsys_mask & (1UL << i)) {
+ if (root->top_cgroup.subsys_mask & (1UL << i)) {
/* Subsystem is in this hierarchy. So we want
* the subsystem state from the new
* cgroup */
/* Subsystem is in this hierarchy. So we want
* the subsystem state from the new
* cgroup */
BUG_ON(!list_empty(&cgrp->children));
/* Rebind all subsystems back to the default hierarchy */
BUG_ON(!list_empty(&cgrp->children));
/* Rebind all subsystems back to the default hierarchy */
- rebind_subsystems(&cgroup_dummy_root, root->subsys_mask);
+ rebind_subsystems(&cgroup_dummy_root, cgrp->subsys_mask);
/*
* Release all the links from cset_links to this hierarchy's
/*
* Release all the links from cset_links to this hierarchy's
ss->root = dst_root;
css->cgroup = dst_top;
ss->root = dst_root;
css->cgroup = dst_top;
- src_root->subsys_mask &= ~(1 << ssid);
- dst_root->subsys_mask |= 1 << ssid;
+ src_top->subsys_mask &= ~(1 << ssid);
+ dst_top->subsys_mask |= 1 << ssid;
if (ss->bind)
ss->bind(css);
if (ss->bind)
ss->bind(css);
int ssid;
for_each_subsys(ss, ssid)
int ssid;
for_each_subsys(ss, ssid)
- if (root->subsys_mask & (1 << ssid))
+ if (root->top_cgroup.subsys_mask & (1 << ssid))
seq_printf(seq, ",%s", ss->name);
if (root->flags & CGRP_ROOT_SANE_BEHAVIOR)
seq_puts(seq, ",sane_behavior");
seq_printf(seq, ",%s", ss->name);
if (root->flags & CGRP_ROOT_SANE_BEHAVIOR)
seq_puts(seq, ",sane_behavior");
if (ret)
goto out_unlock;
if (ret)
goto out_unlock;
- if (opts.subsys_mask != root->subsys_mask || opts.release_agent)
+ if (opts.subsys_mask != root->top_cgroup.subsys_mask || opts.release_agent)
pr_warning("cgroup: option changes via remount are deprecated (pid=%d comm=%s)\n",
task_tgid_nr(current), current->comm);
pr_warning("cgroup: option changes via remount are deprecated (pid=%d comm=%s)\n",
task_tgid_nr(current), current->comm);
- added_mask = opts.subsys_mask & ~root->subsys_mask;
- removed_mask = root->subsys_mask & ~opts.subsys_mask;
+ added_mask = opts.subsys_mask & ~root->top_cgroup.subsys_mask;
+ removed_mask = root->top_cgroup.subsys_mask & ~opts.subsys_mask;
/* Don't allow flags or name to change at remount */
if (((opts.flags ^ root->flags) & CGRP_ROOT_OPTION_MASK) ||
/* Don't allow flags or name to change at remount */
if (((opts.flags ^ root->flags) & CGRP_ROOT_OPTION_MASK) ||
* subsystems) then they must match.
*/
if ((opts.subsys_mask || opts.none) &&
* subsystems) then they must match.
*/
if ((opts.subsys_mask || opts.none) &&
- (opts.subsys_mask != root->subsys_mask)) {
+ (opts.subsys_mask != root->top_cgroup.subsys_mask)) {
if (!name_match)
continue;
ret = -EBUSY;
if (!name_match)
continue;
ret = -EBUSY;
cgroup_get(cgrp);
css_get(css->parent);
cgroup_get(cgrp);
css_get(css->parent);
+ cgrp->subsys_mask |= 1 << ss->id;
+
if (ss->broken_hierarchy && !ss->warned_broken_hierarchy &&
parent->parent) {
pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n",
if (ss->broken_hierarchy && !ss->warned_broken_hierarchy &&
parent->parent) {
pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n",
/* let's create and online css's */
for_each_subsys(ss, ssid) {
/* let's create and online css's */
for_each_subsys(ss, ssid) {
- if (root->subsys_mask & (1 << ssid)) {
+ if (root->top_cgroup.subsys_mask & (1 << ssid)) {
err = create_css(cgrp, ss);
if (err)
goto err_destroy;
err = create_css(cgrp, ss);
if (err)
goto err_destroy;
queue_work(cgroup_destroy_wq, &css->destroy_work);
}
queue_work(cgroup_destroy_wq, &css->destroy_work);
}
-/**
- * kill_css - destroy a css
- * @css: css to destroy
- *
- * This function initiates destruction of @css by removing cgroup interface
- * files and putting its base reference. ->css_offline() will be invoked
- * asynchronously once css_tryget() is guaranteed to fail and when the
- * reference count reaches zero, @css will be released.
- */
-static void kill_css(struct cgroup_subsys_state *css)
+static void __kill_css(struct cgroup_subsys_state *css)
+ lockdep_assert_held(&cgroup_tree_mutex);
+
/*
* This must happen before css is disassociated with its cgroup.
* See seq_css() for details.
/*
* This must happen before css is disassociated with its cgroup.
* See seq_css() for details.
percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn);
}
percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn);
}
+/**
+ * kill_css - destroy a css
+ * @css: css to destroy
+ *
+ * This function initiates destruction of @css by removing cgroup interface
+ * files and putting its base reference. ->css_offline() will be invoked
+ * asynchronously once css_tryget() is guaranteed to fail and when the
+ * reference count reaches zero, @css will be released.
+ */
+static void kill_css(struct cgroup_subsys_state *css)
+{
+ struct cgroup *cgrp = css->cgroup;
+
+ lockdep_assert_held(&cgroup_tree_mutex);
+
+ /* if already killed, noop */
+ if (cgrp->subsys_mask & (1 << css->ss->id)) {
+ cgrp->subsys_mask &= ~(1 << css->ss->id);
+ __kill_css(css);
+ }
+}
+
/**
* cgroup_destroy_locked - the first stage of cgroup destruction
* @cgrp: cgroup to be destroyed
/**
* cgroup_destroy_locked - the first stage of cgroup destruction
* @cgrp: cgroup to be destroyed
- cgroup_dummy_root.subsys_mask |= 1 << ss->id;
+ cgroup_dummy_root.top_cgroup.subsys_mask |= 1 << ss->id;
mutex_unlock(&cgroup_mutex);
mutex_unlock(&cgroup_tree_mutex);
mutex_unlock(&cgroup_mutex);
mutex_unlock(&cgroup_tree_mutex);
seq_printf(m, "%d:", root->hierarchy_id);
for_each_subsys(ss, ssid)
seq_printf(m, "%d:", root->hierarchy_id);
for_each_subsys(ss, ssid)
- if (root->subsys_mask & (1 << ssid))
+ if (root->top_cgroup.subsys_mask & (1 << ssid))
seq_printf(m, "%s%s", count++ ? "," : "", ss->name);
if (strlen(root->name))
seq_printf(m, "%sname=%s", count ? "," : "",
seq_printf(m, "%s%s", count++ ? "," : "", ss->name);
if (strlen(root->name))
seq_printf(m, "%sname=%s", count ? "," : "",