diff options
Diffstat (limited to 'kernel/cpuset.c')
-rw-r--r-- | kernel/cpuset.c | 109 |
1 files changed, 35 insertions, 74 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index d5738910c34c..276ce7e4f1ab 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -227,10 +227,6 @@ static struct cpuset top_cpuset = { | |||
227 | * The task_struct fields mems_allowed and mems_generation may only | 227 | * The task_struct fields mems_allowed and mems_generation may only |
228 | * be accessed in the context of that task, so require no locks. | 228 | * be accessed in the context of that task, so require no locks. |
229 | * | 229 | * |
230 | * The cpuset_common_file_write handler for operations that modify | ||
231 | * the cpuset hierarchy holds cgroup_mutex across the entire operation, | ||
232 | * single threading all such cpuset modifications across the system. | ||
233 | * | ||
234 | * The cpuset_common_file_read() handlers only hold callback_mutex across | 230 | * The cpuset_common_file_read() handlers only hold callback_mutex across |
235 | * small pieces of code, such as when reading out possibly multi-word | 231 | * small pieces of code, such as when reading out possibly multi-word |
236 | * cpumasks and nodemasks. | 232 | * cpumasks and nodemasks. |
@@ -772,7 +768,7 @@ static void cpuset_change_cpumask(struct task_struct *tsk, | |||
772 | * @cs: the cpuset to consider | 768 | * @cs: the cpuset to consider |
773 | * @buf: buffer of cpu numbers written to this cpuset | 769 | * @buf: buffer of cpu numbers written to this cpuset |
774 | */ | 770 | */ |
775 | static int update_cpumask(struct cpuset *cs, char *buf) | 771 | static int update_cpumask(struct cpuset *cs, const char *buf) |
776 | { | 772 | { |
777 | struct cpuset trialcs; | 773 | struct cpuset trialcs; |
778 | struct cgroup_scanner scan; | 774 | struct cgroup_scanner scan; |
@@ -792,7 +788,6 @@ static int update_cpumask(struct cpuset *cs, char *buf) | |||
792 | * that parsing. The validate_change() call ensures that cpusets | 788 | * that parsing. The validate_change() call ensures that cpusets |
793 | * with tasks have cpus. | 789 | * with tasks have cpus. |
794 | */ | 790 | */ |
795 | buf = strstrip(buf); | ||
796 | if (!*buf) { | 791 | if (!*buf) { |
797 | cpus_clear(trialcs.cpus_allowed); | 792 | cpus_clear(trialcs.cpus_allowed); |
798 | } else { | 793 | } else { |
@@ -902,7 +897,7 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from, | |||
902 | 897 | ||
903 | static void *cpuset_being_rebound; | 898 | static void *cpuset_being_rebound; |
904 | 899 | ||
905 | static int update_nodemask(struct cpuset *cs, char *buf) | 900 | static int update_nodemask(struct cpuset *cs, const char *buf) |
906 | { | 901 | { |
907 | struct cpuset trialcs; | 902 | struct cpuset trialcs; |
908 | nodemask_t oldmem; | 903 | nodemask_t oldmem; |
@@ -929,7 +924,6 @@ static int update_nodemask(struct cpuset *cs, char *buf) | |||
929 | * that parsing. The validate_change() call ensures that cpusets | 924 | * that parsing. The validate_change() call ensures that cpusets |
930 | * with tasks have memory. | 925 | * with tasks have memory. |
931 | */ | 926 | */ |
932 | buf = strstrip(buf); | ||
933 | if (!*buf) { | 927 | if (!*buf) { |
934 | nodes_clear(trialcs.mems_allowed); | 928 | nodes_clear(trialcs.mems_allowed); |
935 | } else { | 929 | } else { |
@@ -1256,72 +1250,14 @@ typedef enum { | |||
1256 | FILE_SPREAD_SLAB, | 1250 | FILE_SPREAD_SLAB, |
1257 | } cpuset_filetype_t; | 1251 | } cpuset_filetype_t; |
1258 | 1252 | ||
1259 | static ssize_t cpuset_common_file_write(struct cgroup *cont, | ||
1260 | struct cftype *cft, | ||
1261 | struct file *file, | ||
1262 | const char __user *userbuf, | ||
1263 | size_t nbytes, loff_t *unused_ppos) | ||
1264 | { | ||
1265 | struct cpuset *cs = cgroup_cs(cont); | ||
1266 | cpuset_filetype_t type = cft->private; | ||
1267 | char *buffer; | ||
1268 | int retval = 0; | ||
1269 | |||
1270 | /* Crude upper limit on largest legitimate cpulist user might write. */ | ||
1271 | if (nbytes > 100U + 6 * max(NR_CPUS, MAX_NUMNODES)) | ||
1272 | return -E2BIG; | ||
1273 | |||
1274 | /* +1 for nul-terminator */ | ||
1275 | buffer = kmalloc(nbytes + 1, GFP_KERNEL); | ||
1276 | if (!buffer) | ||
1277 | return -ENOMEM; | ||
1278 | |||
1279 | if (copy_from_user(buffer, userbuf, nbytes)) { | ||
1280 | retval = -EFAULT; | ||
1281 | goto out1; | ||
1282 | } | ||
1283 | buffer[nbytes] = 0; /* nul-terminate */ | ||
1284 | |||
1285 | cgroup_lock(); | ||
1286 | |||
1287 | if (cgroup_is_removed(cont)) { | ||
1288 | retval = -ENODEV; | ||
1289 | goto out2; | ||
1290 | } | ||
1291 | |||
1292 | switch (type) { | ||
1293 | case FILE_CPULIST: | ||
1294 | retval = update_cpumask(cs, buffer); | ||
1295 | break; | ||
1296 | case FILE_MEMLIST: | ||
1297 | retval = update_nodemask(cs, buffer); | ||
1298 | break; | ||
1299 | default: | ||
1300 | retval = -EINVAL; | ||
1301 | goto out2; | ||
1302 | } | ||
1303 | |||
1304 | if (retval == 0) | ||
1305 | retval = nbytes; | ||
1306 | out2: | ||
1307 | cgroup_unlock(); | ||
1308 | out1: | ||
1309 | kfree(buffer); | ||
1310 | return retval; | ||
1311 | } | ||
1312 | |||
1313 | static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val) | 1253 | static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val) |
1314 | { | 1254 | { |
1315 | int retval = 0; | 1255 | int retval = 0; |
1316 | struct cpuset *cs = cgroup_cs(cgrp); | 1256 | struct cpuset *cs = cgroup_cs(cgrp); |
1317 | cpuset_filetype_t type = cft->private; | 1257 | cpuset_filetype_t type = cft->private; |
1318 | 1258 | ||
1319 | cgroup_lock(); | 1259 | if (!cgroup_lock_live_group(cgrp)) |
1320 | |||
1321 | if (cgroup_is_removed(cgrp)) { | ||
1322 | cgroup_unlock(); | ||
1323 | return -ENODEV; | 1260 | return -ENODEV; |
1324 | } | ||
1325 | 1261 | ||
1326 | switch (type) { | 1262 | switch (type) { |
1327 | case FILE_CPU_EXCLUSIVE: | 1263 | case FILE_CPU_EXCLUSIVE: |
@@ -1367,12 +1303,9 @@ static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val) | |||
1367 | struct cpuset *cs = cgroup_cs(cgrp); | 1303 | struct cpuset *cs = cgroup_cs(cgrp); |
1368 | cpuset_filetype_t type = cft->private; | 1304 | cpuset_filetype_t type = cft->private; |
1369 | 1305 | ||
1370 | cgroup_lock(); | 1306 | if (!cgroup_lock_live_group(cgrp)) |
1371 | |||
1372 | if (cgroup_is_removed(cgrp)) { | ||
1373 | cgroup_unlock(); | ||
1374 | return -ENODEV; | 1307 | return -ENODEV; |
1375 | } | 1308 | |
1376 | switch (type) { | 1309 | switch (type) { |
1377 | case FILE_SCHED_RELAX_DOMAIN_LEVEL: | 1310 | case FILE_SCHED_RELAX_DOMAIN_LEVEL: |
1378 | retval = update_relax_domain_level(cs, val); | 1311 | retval = update_relax_domain_level(cs, val); |
@@ -1386,6 +1319,32 @@ static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val) | |||
1386 | } | 1319 | } |
1387 | 1320 | ||
1388 | /* | 1321 | /* |
1322 | * Common handling for a write to a "cpus" or "mems" file. | ||
1323 | */ | ||
1324 | static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft, | ||
1325 | const char *buf) | ||
1326 | { | ||
1327 | int retval = 0; | ||
1328 | |||
1329 | if (!cgroup_lock_live_group(cgrp)) | ||
1330 | return -ENODEV; | ||
1331 | |||
1332 | switch (cft->private) { | ||
1333 | case FILE_CPULIST: | ||
1334 | retval = update_cpumask(cgroup_cs(cgrp), buf); | ||
1335 | break; | ||
1336 | case FILE_MEMLIST: | ||
1337 | retval = update_nodemask(cgroup_cs(cgrp), buf); | ||
1338 | break; | ||
1339 | default: | ||
1340 | retval = -EINVAL; | ||
1341 | break; | ||
1342 | } | ||
1343 | cgroup_unlock(); | ||
1344 | return retval; | ||
1345 | } | ||
1346 | |||
1347 | /* | ||
1389 | * These ascii lists should be read in a single call, by using a user | 1348 | * These ascii lists should be read in a single call, by using a user |
1390 | * buffer large enough to hold the entire map. If read in smaller | 1349 | * buffer large enough to hold the entire map. If read in smaller |
1391 | * chunks, there is no guarantee of atomicity. Since the display format | 1350 | * chunks, there is no guarantee of atomicity. Since the display format |
@@ -1504,14 +1463,16 @@ static struct cftype files[] = { | |||
1504 | { | 1463 | { |
1505 | .name = "cpus", | 1464 | .name = "cpus", |
1506 | .read = cpuset_common_file_read, | 1465 | .read = cpuset_common_file_read, |
1507 | .write = cpuset_common_file_write, | 1466 | .write_string = cpuset_write_resmask, |
1467 | .max_write_len = (100U + 6 * NR_CPUS), | ||
1508 | .private = FILE_CPULIST, | 1468 | .private = FILE_CPULIST, |
1509 | }, | 1469 | }, |
1510 | 1470 | ||
1511 | { | 1471 | { |
1512 | .name = "mems", | 1472 | .name = "mems", |
1513 | .read = cpuset_common_file_read, | 1473 | .read = cpuset_common_file_read, |
1514 | .write = cpuset_common_file_write, | 1474 | .write_string = cpuset_write_resmask, |
1475 | .max_write_len = (100U + 6 * MAX_NUMNODES), | ||
1515 | .private = FILE_MEMLIST, | 1476 | .private = FILE_MEMLIST, |
1516 | }, | 1477 | }, |
1517 | 1478 | ||