|
@@ -243,6 +243,11 @@ static int notify_on_release(const struct cgroup *cgrp)
|
|
|
return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
|
|
|
}
|
|
|
|
|
|
+static int clone_children(const struct cgroup *cgrp)
|
|
|
+{
|
|
|
+ return test_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* for_each_subsys() allows you to iterate on each subsystem attached to
|
|
|
* an active hierarchy
|
|
@@ -1040,6 +1045,8 @@ static int cgroup_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|
|
seq_puts(seq, ",noprefix");
|
|
|
if (strlen(root->release_agent_path))
|
|
|
seq_printf(seq, ",release_agent=%s", root->release_agent_path);
|
|
|
+ if (clone_children(&root->top_cgroup))
|
|
|
+ seq_puts(seq, ",clone_children");
|
|
|
if (strlen(root->name))
|
|
|
seq_printf(seq, ",name=%s", root->name);
|
|
|
mutex_unlock(&cgroup_mutex);
|
|
@@ -1050,6 +1057,7 @@ struct cgroup_sb_opts {
|
|
|
unsigned long subsys_bits;
|
|
|
unsigned long flags;
|
|
|
char *release_agent;
|
|
|
+ bool clone_children;
|
|
|
char *name;
|
|
|
/* User explicitly requested empty subsystem */
|
|
|
bool none;
|
|
@@ -1097,6 +1105,8 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
|
|
|
opts->none = true;
|
|
|
} else if (!strcmp(token, "noprefix")) {
|
|
|
set_bit(ROOT_NOPREFIX, &opts->flags);
|
|
|
+ } else if (!strcmp(token, "clone_children")) {
|
|
|
+ opts->clone_children = true;
|
|
|
} else if (!strncmp(token, "release_agent=", 14)) {
|
|
|
/* Specifying two release agents is forbidden */
|
|
|
if (opts->release_agent)
|
|
@@ -1355,6 +1365,8 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
|
|
|
strcpy(root->release_agent_path, opts->release_agent);
|
|
|
if (opts->name)
|
|
|
strcpy(root->name, opts->name);
|
|
|
+ if (opts->clone_children)
|
|
|
+ set_bit(CGRP_CLONE_CHILDREN, &root->top_cgroup.flags);
|
|
|
return root;
|
|
|
}
|
|
|
|
|
@@ -3173,6 +3185,23 @@ fail:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static u64 cgroup_clone_children_read(struct cgroup *cgrp,
|
|
|
+ struct cftype *cft)
|
|
|
+{
|
|
|
+ return clone_children(cgrp);
|
|
|
+}
|
|
|
+
|
|
|
+static int cgroup_clone_children_write(struct cgroup *cgrp,
|
|
|
+ struct cftype *cft,
|
|
|
+ u64 val)
|
|
|
+{
|
|
|
+ if (val)
|
|
|
+ set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
|
|
|
+ else
|
|
|
+ clear_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* for the common functions, 'private' gives the type of file
|
|
|
*/
|
|
@@ -3203,6 +3232,11 @@ static struct cftype files[] = {
|
|
|
.write_string = cgroup_write_event_control,
|
|
|
.mode = S_IWUGO,
|
|
|
},
|
|
|
+ {
|
|
|
+ .name = "cgroup.clone_children",
|
|
|
+ .read_u64 = cgroup_clone_children_read,
|
|
|
+ .write_u64 = cgroup_clone_children_write,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct cftype cft_release_agent = {
|
|
@@ -3332,6 +3366,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
|
|
|
if (notify_on_release(parent))
|
|
|
set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
|
|
|
|
|
|
+ if (clone_children(parent))
|
|
|
+ set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
|
|
|
+
|
|
|
for_each_subsys(root, ss) {
|
|
|
struct cgroup_subsys_state *css = ss->create(ss, cgrp);
|
|
|
|
|
@@ -3346,6 +3383,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
|
|
|
goto err_destroy;
|
|
|
}
|
|
|
/* At error, ->destroy() callback has to free assigned ID. */
|
|
|
+ if (clone_children(parent) && ss->post_clone)
|
|
|
+ ss->post_clone(ss, cgrp);
|
|
|
}
|
|
|
|
|
|
cgroup_lock_hierarchy(root);
|