diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 129 |
1 files changed, 100 insertions, 29 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9270d532ec3c..5cf366965d0c 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -243,6 +243,11 @@ static int notify_on_release(const struct cgroup *cgrp) | |||
243 | return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); | 243 | return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); |
244 | } | 244 | } |
245 | 245 | ||
246 | static int clone_children(const struct cgroup *cgrp) | ||
247 | { | ||
248 | return test_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); | ||
249 | } | ||
250 | |||
246 | /* | 251 | /* |
247 | * for_each_subsys() allows you to iterate on each subsystem attached to | 252 | * for_each_subsys() allows you to iterate on each subsystem attached to |
248 | * an active hierarchy | 253 | * an active hierarchy |
@@ -1040,6 +1045,8 @@ static int cgroup_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
1040 | seq_puts(seq, ",noprefix"); | 1045 | seq_puts(seq, ",noprefix"); |
1041 | if (strlen(root->release_agent_path)) | 1046 | if (strlen(root->release_agent_path)) |
1042 | seq_printf(seq, ",release_agent=%s", root->release_agent_path); | 1047 | seq_printf(seq, ",release_agent=%s", root->release_agent_path); |
1048 | if (clone_children(&root->top_cgroup)) | ||
1049 | seq_puts(seq, ",clone_children"); | ||
1043 | if (strlen(root->name)) | 1050 | if (strlen(root->name)) |
1044 | seq_printf(seq, ",name=%s", root->name); | 1051 | seq_printf(seq, ",name=%s", root->name); |
1045 | mutex_unlock(&cgroup_mutex); | 1052 | mutex_unlock(&cgroup_mutex); |
@@ -1050,6 +1057,7 @@ struct cgroup_sb_opts { | |||
1050 | unsigned long subsys_bits; | 1057 | unsigned long subsys_bits; |
1051 | unsigned long flags; | 1058 | unsigned long flags; |
1052 | char *release_agent; | 1059 | char *release_agent; |
1060 | bool clone_children; | ||
1053 | char *name; | 1061 | char *name; |
1054 | /* User explicitly requested empty subsystem */ | 1062 | /* User explicitly requested empty subsystem */ |
1055 | bool none; | 1063 | bool none; |
@@ -1066,7 +1074,8 @@ struct cgroup_sb_opts { | |||
1066 | */ | 1074 | */ |
1067 | static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) | 1075 | static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) |
1068 | { | 1076 | { |
1069 | char *token, *o = data ?: "all"; | 1077 | char *token, *o = data; |
1078 | bool all_ss = false, one_ss = false; | ||
1070 | unsigned long mask = (unsigned long)-1; | 1079 | unsigned long mask = (unsigned long)-1; |
1071 | int i; | 1080 | int i; |
1072 | bool module_pin_failed = false; | 1081 | bool module_pin_failed = false; |
@@ -1082,22 +1091,27 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) | |||
1082 | while ((token = strsep(&o, ",")) != NULL) { | 1091 | while ((token = strsep(&o, ",")) != NULL) { |
1083 | if (!*token) | 1092 | if (!*token) |
1084 | return -EINVAL; | 1093 | return -EINVAL; |
1085 | if (!strcmp(token, "all")) { | 1094 | if (!strcmp(token, "none")) { |
1086 | /* Add all non-disabled subsystems */ | ||
1087 | opts->subsys_bits = 0; | ||
1088 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | ||
1089 | struct cgroup_subsys *ss = subsys[i]; | ||
1090 | if (ss == NULL) | ||
1091 | continue; | ||
1092 | if (!ss->disabled) | ||
1093 | opts->subsys_bits |= 1ul << i; | ||
1094 | } | ||
1095 | } else if (!strcmp(token, "none")) { | ||
1096 | /* Explicitly have no subsystems */ | 1095 | /* Explicitly have no subsystems */ |
1097 | opts->none = true; | 1096 | opts->none = true; |
1098 | } else if (!strcmp(token, "noprefix")) { | 1097 | continue; |
1098 | } | ||
1099 | if (!strcmp(token, "all")) { | ||
1100 | /* Mutually exclusive option 'all' + subsystem name */ | ||
1101 | if (one_ss) | ||
1102 | return -EINVAL; | ||
1103 | all_ss = true; | ||
1104 | continue; | ||
1105 | } | ||
1106 | if (!strcmp(token, "noprefix")) { | ||
1099 | set_bit(ROOT_NOPREFIX, &opts->flags); | 1107 | set_bit(ROOT_NOPREFIX, &opts->flags); |
1100 | } else if (!strncmp(token, "release_agent=", 14)) { | 1108 | continue; |
1109 | } | ||
1110 | if (!strcmp(token, "clone_children")) { | ||
1111 | opts->clone_children = true; | ||
1112 | continue; | ||
1113 | } | ||
1114 | if (!strncmp(token, "release_agent=", 14)) { | ||
1101 | /* Specifying two release agents is forbidden */ | 1115 | /* Specifying two release agents is forbidden */ |
1102 | if (opts->release_agent) | 1116 | if (opts->release_agent) |
1103 | return -EINVAL; | 1117 | return -EINVAL; |
@@ -1105,7 +1119,9 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) | |||
1105 | kstrndup(token + 14, PATH_MAX - 1, GFP_KERNEL); | 1119 | kstrndup(token + 14, PATH_MAX - 1, GFP_KERNEL); |
1106 | if (!opts->release_agent) | 1120 | if (!opts->release_agent) |
1107 | return -ENOMEM; | 1121 | return -ENOMEM; |
1108 | } else if (!strncmp(token, "name=", 5)) { | 1122 | continue; |
1123 | } | ||
1124 | if (!strncmp(token, "name=", 5)) { | ||
1109 | const char *name = token + 5; | 1125 | const char *name = token + 5; |
1110 | /* Can't specify an empty name */ | 1126 | /* Can't specify an empty name */ |
1111 | if (!strlen(name)) | 1127 | if (!strlen(name)) |
@@ -1127,20 +1143,44 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) | |||
1127 | GFP_KERNEL); | 1143 | GFP_KERNEL); |
1128 | if (!opts->name) | 1144 | if (!opts->name) |
1129 | return -ENOMEM; | 1145 | return -ENOMEM; |
1130 | } else { | 1146 | |
1131 | struct cgroup_subsys *ss; | 1147 | continue; |
1132 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | 1148 | } |
1133 | ss = subsys[i]; | 1149 | |
1134 | if (ss == NULL) | 1150 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { |
1135 | continue; | 1151 | struct cgroup_subsys *ss = subsys[i]; |
1136 | if (!strcmp(token, ss->name)) { | 1152 | if (ss == NULL) |
1137 | if (!ss->disabled) | 1153 | continue; |
1138 | set_bit(i, &opts->subsys_bits); | 1154 | if (strcmp(token, ss->name)) |
1139 | break; | 1155 | continue; |
1140 | } | 1156 | if (ss->disabled) |
1141 | } | 1157 | continue; |
1142 | if (i == CGROUP_SUBSYS_COUNT) | 1158 | |
1143 | return -ENOENT; | 1159 | /* Mutually exclusive option 'all' + subsystem name */ |
1160 | if (all_ss) | ||
1161 | return -EINVAL; | ||
1162 | set_bit(i, &opts->subsys_bits); | ||
1163 | one_ss = true; | ||
1164 | |||
1165 | break; | ||
1166 | } | ||
1167 | if (i == CGROUP_SUBSYS_COUNT) | ||
1168 | return -ENOENT; | ||
1169 | } | ||
1170 | |||
1171 | /* | ||
1172 | * If the 'all' option was specified select all the subsystems, | ||
1173 | * otherwise 'all, 'none' and a subsystem name options were not | ||
1174 | * specified, let's default to 'all' | ||
1175 | */ | ||
1176 | if (all_ss || (!all_ss && !one_ss && !opts->none)) { | ||
1177 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | ||
1178 | struct cgroup_subsys *ss = subsys[i]; | ||
1179 | if (ss == NULL) | ||
1180 | continue; | ||
1181 | if (ss->disabled) | ||
1182 | continue; | ||
1183 | set_bit(i, &opts->subsys_bits); | ||
1144 | } | 1184 | } |
1145 | } | 1185 | } |
1146 | 1186 | ||
@@ -1355,6 +1395,8 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts) | |||
1355 | strcpy(root->release_agent_path, opts->release_agent); | 1395 | strcpy(root->release_agent_path, opts->release_agent); |
1356 | if (opts->name) | 1396 | if (opts->name) |
1357 | strcpy(root->name, opts->name); | 1397 | strcpy(root->name, opts->name); |
1398 | if (opts->clone_children) | ||
1399 | set_bit(CGRP_CLONE_CHILDREN, &root->top_cgroup.flags); | ||
1358 | return root; | 1400 | return root; |
1359 | } | 1401 | } |
1360 | 1402 | ||
@@ -1880,6 +1922,8 @@ static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft, | |||
1880 | const char *buffer) | 1922 | const char *buffer) |
1881 | { | 1923 | { |
1882 | BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); | 1924 | BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX); |
1925 | if (strlen(buffer) >= PATH_MAX) | ||
1926 | return -EINVAL; | ||
1883 | if (!cgroup_lock_live_group(cgrp)) | 1927 | if (!cgroup_lock_live_group(cgrp)) |
1884 | return -ENODEV; | 1928 | return -ENODEV; |
1885 | strcpy(cgrp->root->release_agent_path, buffer); | 1929 | strcpy(cgrp->root->release_agent_path, buffer); |
@@ -3173,6 +3217,23 @@ fail: | |||
3173 | return ret; | 3217 | return ret; |
3174 | } | 3218 | } |
3175 | 3219 | ||
3220 | static u64 cgroup_clone_children_read(struct cgroup *cgrp, | ||
3221 | struct cftype *cft) | ||
3222 | { | ||
3223 | return clone_children(cgrp); | ||
3224 | } | ||
3225 | |||
3226 | static int cgroup_clone_children_write(struct cgroup *cgrp, | ||
3227 | struct cftype *cft, | ||
3228 | u64 val) | ||
3229 | { | ||
3230 | if (val) | ||
3231 | set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); | ||
3232 | else | ||
3233 | clear_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); | ||
3234 | return 0; | ||
3235 | } | ||
3236 | |||
3176 | /* | 3237 | /* |
3177 | * for the common functions, 'private' gives the type of file | 3238 | * for the common functions, 'private' gives the type of file |
3178 | */ | 3239 | */ |
@@ -3203,6 +3264,11 @@ static struct cftype files[] = { | |||
3203 | .write_string = cgroup_write_event_control, | 3264 | .write_string = cgroup_write_event_control, |
3204 | .mode = S_IWUGO, | 3265 | .mode = S_IWUGO, |
3205 | }, | 3266 | }, |
3267 | { | ||
3268 | .name = "cgroup.clone_children", | ||
3269 | .read_u64 = cgroup_clone_children_read, | ||
3270 | .write_u64 = cgroup_clone_children_write, | ||
3271 | }, | ||
3206 | }; | 3272 | }; |
3207 | 3273 | ||
3208 | static struct cftype cft_release_agent = { | 3274 | static struct cftype cft_release_agent = { |
@@ -3332,6 +3398,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
3332 | if (notify_on_release(parent)) | 3398 | if (notify_on_release(parent)) |
3333 | set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); | 3399 | set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); |
3334 | 3400 | ||
3401 | if (clone_children(parent)) | ||
3402 | set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags); | ||
3403 | |||
3335 | for_each_subsys(root, ss) { | 3404 | for_each_subsys(root, ss) { |
3336 | struct cgroup_subsys_state *css = ss->create(ss, cgrp); | 3405 | struct cgroup_subsys_state *css = ss->create(ss, cgrp); |
3337 | 3406 | ||
@@ -3346,6 +3415,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
3346 | goto err_destroy; | 3415 | goto err_destroy; |
3347 | } | 3416 | } |
3348 | /* At error, ->destroy() callback has to free assigned ID. */ | 3417 | /* At error, ->destroy() callback has to free assigned ID. */ |
3418 | if (clone_children(parent) && ss->post_clone) | ||
3419 | ss->post_clone(ss, cgrp); | ||
3349 | } | 3420 | } |
3350 | 3421 | ||
3351 | cgroup_lock_hierarchy(root); | 3422 | cgroup_lock_hierarchy(root); |