diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2009-01-07 21:08:43 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-08 11:31:11 -0500 |
commit | 645fcc9d2f6946f97a41c8d00edee38f8a6f0060 (patch) | |
tree | 1d7ad63c9e1bace8f0ccac8814be04af92441ebf /kernel/cpuset.c | |
parent | 2341d1b6598c7146d64a5050b53a72a5a819617f (diff) |
cpuset: don't allocate trial cpuset on stack
Impact: cleanups, reduce stack usage
This patch prepares for the next patch. When we convert
cpuset.cpus_allowed to cpumask_var_t, (trialcs = *cs) no longer works.
Another result of this patch is reducing stack usage of trialcs.
sizeof(*cs) can be as large as 148 bytes on x86_64, so it's really not
good to have it on stack.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Mike Travis <travis@sgi.com>
Cc: Paul Menage <menage@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/cpuset.c')
-rw-r--r-- | kernel/cpuset.c | 93 |
1 files changed, 60 insertions, 33 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 1e32e6b380af..f66527bfd216 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -415,6 +415,24 @@ static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q) | |||
415 | is_mem_exclusive(p) <= is_mem_exclusive(q); | 415 | is_mem_exclusive(p) <= is_mem_exclusive(q); |
416 | } | 416 | } |
417 | 417 | ||
418 | /** | ||
419 | * alloc_trial_cpuset - allocate a trial cpuset | ||
420 | * @cs: the cpuset that the trial cpuset duplicates | ||
421 | */ | ||
422 | static struct cpuset *alloc_trial_cpuset(const struct cpuset *cs) | ||
423 | { | ||
424 | return kmemdup(cs, sizeof(*cs), GFP_KERNEL); | ||
425 | } | ||
426 | |||
427 | /** | ||
428 | * free_trial_cpuset - free the trial cpuset | ||
429 | * @trial: the trial cpuset to be freed | ||
430 | */ | ||
431 | static void free_trial_cpuset(struct cpuset *trial) | ||
432 | { | ||
433 | kfree(trial); | ||
434 | } | ||
435 | |||
418 | /* | 436 | /* |
419 | * validate_change() - Used to validate that any proposed cpuset change | 437 | * validate_change() - Used to validate that any proposed cpuset change |
420 | * follows the structural rules for cpusets. | 438 | * follows the structural rules for cpusets. |
@@ -880,10 +898,10 @@ static void update_tasks_cpumask(struct cpuset *cs, struct ptr_heap *heap) | |||
880 | * @cs: the cpuset to consider | 898 | * @cs: the cpuset to consider |
881 | * @buf: buffer of cpu numbers written to this cpuset | 899 | * @buf: buffer of cpu numbers written to this cpuset |
882 | */ | 900 | */ |
883 | static int update_cpumask(struct cpuset *cs, const char *buf) | 901 | static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, |
902 | const char *buf) | ||
884 | { | 903 | { |
885 | struct ptr_heap heap; | 904 | struct ptr_heap heap; |
886 | struct cpuset trialcs; | ||
887 | int retval; | 905 | int retval; |
888 | int is_load_balanced; | 906 | int is_load_balanced; |
889 | 907 | ||
@@ -891,8 +909,6 @@ static int update_cpumask(struct cpuset *cs, const char *buf) | |||
891 | if (cs == &top_cpuset) | 909 | if (cs == &top_cpuset) |
892 | return -EACCES; | 910 | return -EACCES; |
893 | 911 | ||
894 | trialcs = *cs; | ||
895 | |||
896 | /* | 912 | /* |
897 | * An empty cpus_allowed is ok only if the cpuset has no tasks. | 913 | * An empty cpus_allowed is ok only if the cpuset has no tasks. |
898 | * Since cpulist_parse() fails on an empty mask, we special case | 914 | * Since cpulist_parse() fails on an empty mask, we special case |
@@ -900,31 +916,31 @@ static int update_cpumask(struct cpuset *cs, const char *buf) | |||
900 | * with tasks have cpus. | 916 | * with tasks have cpus. |
901 | */ | 917 | */ |
902 | if (!*buf) { | 918 | if (!*buf) { |
903 | cpus_clear(trialcs.cpus_allowed); | 919 | cpus_clear(trialcs->cpus_allowed); |
904 | } else { | 920 | } else { |
905 | retval = cpulist_parse(buf, &trialcs.cpus_allowed); | 921 | retval = cpulist_parse(buf, &trialcs->cpus_allowed); |
906 | if (retval < 0) | 922 | if (retval < 0) |
907 | return retval; | 923 | return retval; |
908 | 924 | ||
909 | if (!cpus_subset(trialcs.cpus_allowed, cpu_online_map)) | 925 | if (!cpus_subset(trialcs->cpus_allowed, cpu_online_map)) |
910 | return -EINVAL; | 926 | return -EINVAL; |
911 | } | 927 | } |
912 | retval = validate_change(cs, &trialcs); | 928 | retval = validate_change(cs, trialcs); |
913 | if (retval < 0) | 929 | if (retval < 0) |
914 | return retval; | 930 | return retval; |
915 | 931 | ||
916 | /* Nothing to do if the cpus didn't change */ | 932 | /* Nothing to do if the cpus didn't change */ |
917 | if (cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed)) | 933 | if (cpus_equal(cs->cpus_allowed, trialcs->cpus_allowed)) |
918 | return 0; | 934 | return 0; |
919 | 935 | ||
920 | retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL); | 936 | retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL); |
921 | if (retval) | 937 | if (retval) |
922 | return retval; | 938 | return retval; |
923 | 939 | ||
924 | is_load_balanced = is_sched_load_balance(&trialcs); | 940 | is_load_balanced = is_sched_load_balance(trialcs); |
925 | 941 | ||
926 | mutex_lock(&callback_mutex); | 942 | mutex_lock(&callback_mutex); |
927 | cs->cpus_allowed = trialcs.cpus_allowed; | 943 | cs->cpus_allowed = trialcs->cpus_allowed; |
928 | mutex_unlock(&callback_mutex); | 944 | mutex_unlock(&callback_mutex); |
929 | 945 | ||
930 | /* | 946 | /* |
@@ -1099,9 +1115,9 @@ done: | |||
1099 | * lock each such tasks mm->mmap_sem, scan its vma's and rebind | 1115 | * lock each such tasks mm->mmap_sem, scan its vma's and rebind |
1100 | * their mempolicies to the cpusets new mems_allowed. | 1116 | * their mempolicies to the cpusets new mems_allowed. |
1101 | */ | 1117 | */ |
1102 | static int update_nodemask(struct cpuset *cs, const char *buf) | 1118 | static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs, |
1119 | const char *buf) | ||
1103 | { | 1120 | { |
1104 | struct cpuset trialcs; | ||
1105 | nodemask_t oldmem; | 1121 | nodemask_t oldmem; |
1106 | int retval; | 1122 | int retval; |
1107 | 1123 | ||
@@ -1112,8 +1128,6 @@ static int update_nodemask(struct cpuset *cs, const char *buf) | |||
1112 | if (cs == &top_cpuset) | 1128 | if (cs == &top_cpuset) |
1113 | return -EACCES; | 1129 | return -EACCES; |
1114 | 1130 | ||
1115 | trialcs = *cs; | ||
1116 | |||
1117 | /* | 1131 | /* |
1118 | * An empty mems_allowed is ok iff there are no tasks in the cpuset. | 1132 | * An empty mems_allowed is ok iff there are no tasks in the cpuset. |
1119 | * Since nodelist_parse() fails on an empty mask, we special case | 1133 | * Since nodelist_parse() fails on an empty mask, we special case |
@@ -1121,27 +1135,27 @@ static int update_nodemask(struct cpuset *cs, const char *buf) | |||
1121 | * with tasks have memory. | 1135 | * with tasks have memory. |
1122 | */ | 1136 | */ |
1123 | if (!*buf) { | 1137 | if (!*buf) { |
1124 | nodes_clear(trialcs.mems_allowed); | 1138 | nodes_clear(trialcs->mems_allowed); |
1125 | } else { | 1139 | } else { |
1126 | retval = nodelist_parse(buf, trialcs.mems_allowed); | 1140 | retval = nodelist_parse(buf, trialcs->mems_allowed); |
1127 | if (retval < 0) | 1141 | if (retval < 0) |
1128 | goto done; | 1142 | goto done; |
1129 | 1143 | ||
1130 | if (!nodes_subset(trialcs.mems_allowed, | 1144 | if (!nodes_subset(trialcs->mems_allowed, |
1131 | node_states[N_HIGH_MEMORY])) | 1145 | node_states[N_HIGH_MEMORY])) |
1132 | return -EINVAL; | 1146 | return -EINVAL; |
1133 | } | 1147 | } |
1134 | oldmem = cs->mems_allowed; | 1148 | oldmem = cs->mems_allowed; |
1135 | if (nodes_equal(oldmem, trialcs.mems_allowed)) { | 1149 | if (nodes_equal(oldmem, trialcs->mems_allowed)) { |
1136 | retval = 0; /* Too easy - nothing to do */ | 1150 | retval = 0; /* Too easy - nothing to do */ |
1137 | goto done; | 1151 | goto done; |
1138 | } | 1152 | } |
1139 | retval = validate_change(cs, &trialcs); | 1153 | retval = validate_change(cs, trialcs); |
1140 | if (retval < 0) | 1154 | if (retval < 0) |
1141 | goto done; | 1155 | goto done; |
1142 | 1156 | ||
1143 | mutex_lock(&callback_mutex); | 1157 | mutex_lock(&callback_mutex); |
1144 | cs->mems_allowed = trialcs.mems_allowed; | 1158 | cs->mems_allowed = trialcs->mems_allowed; |
1145 | cs->mems_generation = cpuset_mems_generation++; | 1159 | cs->mems_generation = cpuset_mems_generation++; |
1146 | mutex_unlock(&callback_mutex); | 1160 | mutex_unlock(&callback_mutex); |
1147 | 1161 | ||
@@ -1181,31 +1195,36 @@ static int update_relax_domain_level(struct cpuset *cs, s64 val) | |||
1181 | static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, | 1195 | static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, |
1182 | int turning_on) | 1196 | int turning_on) |
1183 | { | 1197 | { |
1184 | struct cpuset trialcs; | 1198 | struct cpuset *trialcs; |
1185 | int err; | 1199 | int err; |
1186 | int balance_flag_changed; | 1200 | int balance_flag_changed; |
1187 | 1201 | ||
1188 | trialcs = *cs; | 1202 | trialcs = alloc_trial_cpuset(cs); |
1203 | if (!trialcs) | ||
1204 | return -ENOMEM; | ||
1205 | |||
1189 | if (turning_on) | 1206 | if (turning_on) |
1190 | set_bit(bit, &trialcs.flags); | 1207 | set_bit(bit, &trialcs->flags); |
1191 | else | 1208 | else |
1192 | clear_bit(bit, &trialcs.flags); | 1209 | clear_bit(bit, &trialcs->flags); |
1193 | 1210 | ||
1194 | err = validate_change(cs, &trialcs); | 1211 | err = validate_change(cs, trialcs); |
1195 | if (err < 0) | 1212 | if (err < 0) |
1196 | return err; | 1213 | goto out; |
1197 | 1214 | ||
1198 | balance_flag_changed = (is_sched_load_balance(cs) != | 1215 | balance_flag_changed = (is_sched_load_balance(cs) != |
1199 | is_sched_load_balance(&trialcs)); | 1216 | is_sched_load_balance(trialcs)); |
1200 | 1217 | ||
1201 | mutex_lock(&callback_mutex); | 1218 | mutex_lock(&callback_mutex); |
1202 | cs->flags = trialcs.flags; | 1219 | cs->flags = trialcs->flags; |
1203 | mutex_unlock(&callback_mutex); | 1220 | mutex_unlock(&callback_mutex); |
1204 | 1221 | ||
1205 | if (!cpus_empty(trialcs.cpus_allowed) && balance_flag_changed) | 1222 | if (!cpus_empty(trialcs->cpus_allowed) && balance_flag_changed) |
1206 | async_rebuild_sched_domains(); | 1223 | async_rebuild_sched_domains(); |
1207 | 1224 | ||
1208 | return 0; | 1225 | out: |
1226 | free_trial_cpuset(trialcs); | ||
1227 | return err; | ||
1209 | } | 1228 | } |
1210 | 1229 | ||
1211 | /* | 1230 | /* |
@@ -1453,21 +1472,29 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft, | |||
1453 | const char *buf) | 1472 | const char *buf) |
1454 | { | 1473 | { |
1455 | int retval = 0; | 1474 | int retval = 0; |
1475 | struct cpuset *cs = cgroup_cs(cgrp); | ||
1476 | struct cpuset *trialcs; | ||
1456 | 1477 | ||
1457 | if (!cgroup_lock_live_group(cgrp)) | 1478 | if (!cgroup_lock_live_group(cgrp)) |
1458 | return -ENODEV; | 1479 | return -ENODEV; |
1459 | 1480 | ||
1481 | trialcs = alloc_trial_cpuset(cs); | ||
1482 | if (!trialcs) | ||
1483 | return -ENOMEM; | ||
1484 | |||
1460 | switch (cft->private) { | 1485 | switch (cft->private) { |
1461 | case FILE_CPULIST: | 1486 | case FILE_CPULIST: |
1462 | retval = update_cpumask(cgroup_cs(cgrp), buf); | 1487 | retval = update_cpumask(cs, trialcs, buf); |
1463 | break; | 1488 | break; |
1464 | case FILE_MEMLIST: | 1489 | case FILE_MEMLIST: |
1465 | retval = update_nodemask(cgroup_cs(cgrp), buf); | 1490 | retval = update_nodemask(cs, trialcs, buf); |
1466 | break; | 1491 | break; |
1467 | default: | 1492 | default: |
1468 | retval = -EINVAL; | 1493 | retval = -EINVAL; |
1469 | break; | 1494 | break; |
1470 | } | 1495 | } |
1496 | |||
1497 | free_trial_cpuset(trialcs); | ||
1471 | cgroup_unlock(); | 1498 | cgroup_unlock(); |
1472 | return retval; | 1499 | return retval; |
1473 | } | 1500 | } |