diff options
-rw-r--r-- | include/linux/mempolicy.h | 6 | ||||
-rw-r--r-- | kernel/cpuset.c | 4 | ||||
-rw-r--r-- | mm/mempolicy.c | 64 |
3 files changed, 74 insertions, 0 deletions
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 7af8cb836e78..8b67cf837ca9 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h | |||
@@ -154,6 +154,7 @@ struct mempolicy *get_vma_policy(struct task_struct *task, | |||
154 | 154 | ||
155 | extern void numa_default_policy(void); | 155 | extern void numa_default_policy(void); |
156 | extern void numa_policy_init(void); | 156 | extern void numa_policy_init(void); |
157 | extern void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new); | ||
157 | extern struct mempolicy default_policy; | 158 | extern struct mempolicy default_policy; |
158 | 159 | ||
159 | #else | 160 | #else |
@@ -226,6 +227,11 @@ static inline void numa_default_policy(void) | |||
226 | { | 227 | { |
227 | } | 228 | } |
228 | 229 | ||
230 | static inline void numa_policy_rebind(const nodemask_t *old, | ||
231 | const nodemask_t *new) | ||
232 | { | ||
233 | } | ||
234 | |||
229 | #endif /* CONFIG_NUMA */ | 235 | #endif /* CONFIG_NUMA */ |
230 | #endif /* __KERNEL__ */ | 236 | #endif /* __KERNEL__ */ |
231 | 237 | ||
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 6633f3fb6417..5a737ed9dac7 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/kmod.h> | 33 | #include <linux/kmod.h> |
34 | #include <linux/list.h> | 34 | #include <linux/list.h> |
35 | #include <linux/mempolicy.h> | ||
35 | #include <linux/mm.h> | 36 | #include <linux/mm.h> |
36 | #include <linux/module.h> | 37 | #include <linux/module.h> |
37 | #include <linux/mount.h> | 38 | #include <linux/mount.h> |
@@ -600,6 +601,7 @@ static void refresh_mems(void) | |||
600 | 601 | ||
601 | if (current->cpuset_mems_generation != my_cpusets_mem_gen) { | 602 | if (current->cpuset_mems_generation != my_cpusets_mem_gen) { |
602 | struct cpuset *cs; | 603 | struct cpuset *cs; |
604 | nodemask_t oldmem = current->mems_allowed; | ||
603 | 605 | ||
604 | down(&callback_sem); | 606 | down(&callback_sem); |
605 | task_lock(current); | 607 | task_lock(current); |
@@ -608,6 +610,8 @@ static void refresh_mems(void) | |||
608 | current->cpuset_mems_generation = cs->mems_generation; | 610 | current->cpuset_mems_generation = cs->mems_generation; |
609 | task_unlock(current); | 611 | task_unlock(current); |
610 | up(&callback_sem); | 612 | up(&callback_sem); |
613 | if (!nodes_equal(oldmem, current->mems_allowed)) | ||
614 | numa_policy_rebind(&oldmem, ¤t->mems_allowed); | ||
611 | } | 615 | } |
612 | } | 616 | } |
613 | 617 | ||
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 2076b1542b8a..5abc57c2b8bd 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -457,6 +457,7 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask, | |||
457 | struct vm_area_struct *vma = NULL; | 457 | struct vm_area_struct *vma = NULL; |
458 | struct mempolicy *pol = current->mempolicy; | 458 | struct mempolicy *pol = current->mempolicy; |
459 | 459 | ||
460 | cpuset_update_current_mems_allowed(); | ||
460 | if (flags & ~(unsigned long)(MPOL_F_NODE|MPOL_F_ADDR)) | 461 | if (flags & ~(unsigned long)(MPOL_F_NODE|MPOL_F_ADDR)) |
461 | return -EINVAL; | 462 | return -EINVAL; |
462 | if (flags & MPOL_F_ADDR) { | 463 | if (flags & MPOL_F_ADDR) { |
@@ -1206,3 +1207,66 @@ void numa_default_policy(void) | |||
1206 | { | 1207 | { |
1207 | do_set_mempolicy(MPOL_DEFAULT, NULL); | 1208 | do_set_mempolicy(MPOL_DEFAULT, NULL); |
1208 | } | 1209 | } |
1210 | |||
1211 | /* Migrate a policy to a different set of nodes */ | ||
1212 | static void rebind_policy(struct mempolicy *pol, const nodemask_t *old, | ||
1213 | const nodemask_t *new) | ||
1214 | { | ||
1215 | nodemask_t tmp; | ||
1216 | |||
1217 | if (!pol) | ||
1218 | return; | ||
1219 | |||
1220 | switch (pol->policy) { | ||
1221 | case MPOL_DEFAULT: | ||
1222 | break; | ||
1223 | case MPOL_INTERLEAVE: | ||
1224 | nodes_remap(tmp, pol->v.nodes, *old, *new); | ||
1225 | pol->v.nodes = tmp; | ||
1226 | current->il_next = node_remap(current->il_next, *old, *new); | ||
1227 | break; | ||
1228 | case MPOL_PREFERRED: | ||
1229 | pol->v.preferred_node = node_remap(pol->v.preferred_node, | ||
1230 | *old, *new); | ||
1231 | break; | ||
1232 | case MPOL_BIND: { | ||
1233 | nodemask_t nodes; | ||
1234 | struct zone **z; | ||
1235 | struct zonelist *zonelist; | ||
1236 | |||
1237 | nodes_clear(nodes); | ||
1238 | for (z = pol->v.zonelist->zones; *z; z++) | ||
1239 | node_set((*z)->zone_pgdat->node_id, nodes); | ||
1240 | nodes_remap(tmp, nodes, *old, *new); | ||
1241 | nodes = tmp; | ||
1242 | |||
1243 | zonelist = bind_zonelist(&nodes); | ||
1244 | |||
1245 | /* If no mem, then zonelist is NULL and we keep old zonelist. | ||
1246 | * If that old zonelist has no remaining mems_allowed nodes, | ||
1247 | * then zonelist_policy() will "FALL THROUGH" to MPOL_DEFAULT. | ||
1248 | */ | ||
1249 | |||
1250 | if (zonelist) { | ||
1251 | /* Good - got mem - substitute new zonelist */ | ||
1252 | kfree(pol->v.zonelist); | ||
1253 | pol->v.zonelist = zonelist; | ||
1254 | } | ||
1255 | break; | ||
1256 | } | ||
1257 | default: | ||
1258 | BUG(); | ||
1259 | break; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | /* | ||
1264 | * Someone moved this task to different nodes. Fixup mempolicies. | ||
1265 | * | ||
1266 | * TODO - fixup current->mm->vma and shmfs/tmpfs/hugetlbfs policies as well, | ||
1267 | * once we have a cpuset mechanism to mark which cpuset subtree is migrating. | ||
1268 | */ | ||
1269 | void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new) | ||
1270 | { | ||
1271 | rebind_policy(current->mempolicy, old, new); | ||
1272 | } | ||