diff options
Diffstat (limited to 'kernel/cpuset.c')
-rw-r--r-- | kernel/cpuset.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 7430640f9816..f63383e01ec7 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -87,6 +87,7 @@ struct cpuset { | |||
87 | typedef enum { | 87 | typedef enum { |
88 | CS_CPU_EXCLUSIVE, | 88 | CS_CPU_EXCLUSIVE, |
89 | CS_MEM_EXCLUSIVE, | 89 | CS_MEM_EXCLUSIVE, |
90 | CS_MEMORY_MIGRATE, | ||
90 | CS_REMOVED, | 91 | CS_REMOVED, |
91 | CS_NOTIFY_ON_RELEASE | 92 | CS_NOTIFY_ON_RELEASE |
92 | } cpuset_flagbits_t; | 93 | } cpuset_flagbits_t; |
@@ -112,6 +113,11 @@ static inline int notify_on_release(const struct cpuset *cs) | |||
112 | return !!test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags); | 113 | return !!test_bit(CS_NOTIFY_ON_RELEASE, &cs->flags); |
113 | } | 114 | } |
114 | 115 | ||
116 | static inline int is_memory_migrate(const struct cpuset *cs) | ||
117 | { | ||
118 | return !!test_bit(CS_MEMORY_MIGRATE, &cs->flags); | ||
119 | } | ||
120 | |||
115 | /* | 121 | /* |
116 | * Increment this atomic integer everytime any cpuset changes its | 122 | * Increment this atomic integer everytime any cpuset changes its |
117 | * mems_allowed value. Users of cpusets can track this generation | 123 | * mems_allowed value. Users of cpusets can track this generation |
@@ -602,16 +608,24 @@ static void refresh_mems(void) | |||
602 | if (current->cpuset_mems_generation != my_cpusets_mem_gen) { | 608 | if (current->cpuset_mems_generation != my_cpusets_mem_gen) { |
603 | struct cpuset *cs; | 609 | struct cpuset *cs; |
604 | nodemask_t oldmem = current->mems_allowed; | 610 | nodemask_t oldmem = current->mems_allowed; |
611 | int migrate; | ||
605 | 612 | ||
606 | down(&callback_sem); | 613 | down(&callback_sem); |
607 | task_lock(current); | 614 | task_lock(current); |
608 | cs = current->cpuset; | 615 | cs = current->cpuset; |
616 | migrate = is_memory_migrate(cs); | ||
609 | guarantee_online_mems(cs, ¤t->mems_allowed); | 617 | guarantee_online_mems(cs, ¤t->mems_allowed); |
610 | current->cpuset_mems_generation = cs->mems_generation; | 618 | current->cpuset_mems_generation = cs->mems_generation; |
611 | task_unlock(current); | 619 | task_unlock(current); |
612 | up(&callback_sem); | 620 | up(&callback_sem); |
613 | if (!nodes_equal(oldmem, current->mems_allowed)) | 621 | if (!nodes_equal(oldmem, current->mems_allowed)) { |
614 | numa_policy_rebind(&oldmem, ¤t->mems_allowed); | 622 | numa_policy_rebind(&oldmem, ¤t->mems_allowed); |
623 | if (migrate) { | ||
624 | do_migrate_pages(current->mm, &oldmem, | ||
625 | ¤t->mems_allowed, | ||
626 | MPOL_MF_MOVE_ALL); | ||
627 | } | ||
628 | } | ||
615 | } | 629 | } |
616 | } | 630 | } |
617 | 631 | ||
@@ -795,7 +809,7 @@ static int update_nodemask(struct cpuset *cs, char *buf) | |||
795 | /* | 809 | /* |
796 | * update_flag - read a 0 or a 1 in a file and update associated flag | 810 | * update_flag - read a 0 or a 1 in a file and update associated flag |
797 | * bit: the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, | 811 | * bit: the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE, |
798 | * CS_NOTIFY_ON_RELEASE) | 812 | * CS_NOTIFY_ON_RELEASE, CS_MEMORY_MIGRATE) |
799 | * cs: the cpuset to update | 813 | * cs: the cpuset to update |
800 | * buf: the buffer where we read the 0 or 1 | 814 | * buf: the buffer where we read the 0 or 1 |
801 | * | 815 | * |
@@ -848,6 +862,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) | |||
848 | struct task_struct *tsk; | 862 | struct task_struct *tsk; |
849 | struct cpuset *oldcs; | 863 | struct cpuset *oldcs; |
850 | cpumask_t cpus; | 864 | cpumask_t cpus; |
865 | nodemask_t from, to; | ||
851 | 866 | ||
852 | if (sscanf(pidbuf, "%d", &pid) != 1) | 867 | if (sscanf(pidbuf, "%d", &pid) != 1) |
853 | return -EIO; | 868 | return -EIO; |
@@ -893,7 +908,12 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) | |||
893 | guarantee_online_cpus(cs, &cpus); | 908 | guarantee_online_cpus(cs, &cpus); |
894 | set_cpus_allowed(tsk, cpus); | 909 | set_cpus_allowed(tsk, cpus); |
895 | 910 | ||
911 | from = oldcs->mems_allowed; | ||
912 | to = cs->mems_allowed; | ||
913 | |||
896 | up(&callback_sem); | 914 | up(&callback_sem); |
915 | if (is_memory_migrate(cs)) | ||
916 | do_migrate_pages(tsk->mm, &from, &to, MPOL_MF_MOVE_ALL); | ||
897 | put_task_struct(tsk); | 917 | put_task_struct(tsk); |
898 | if (atomic_dec_and_test(&oldcs->count)) | 918 | if (atomic_dec_and_test(&oldcs->count)) |
899 | check_for_release(oldcs, ppathbuf); | 919 | check_for_release(oldcs, ppathbuf); |
@@ -905,6 +925,7 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) | |||
905 | typedef enum { | 925 | typedef enum { |
906 | FILE_ROOT, | 926 | FILE_ROOT, |
907 | FILE_DIR, | 927 | FILE_DIR, |
928 | FILE_MEMORY_MIGRATE, | ||
908 | FILE_CPULIST, | 929 | FILE_CPULIST, |
909 | FILE_MEMLIST, | 930 | FILE_MEMLIST, |
910 | FILE_CPU_EXCLUSIVE, | 931 | FILE_CPU_EXCLUSIVE, |
@@ -960,6 +981,9 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us | |||
960 | case FILE_NOTIFY_ON_RELEASE: | 981 | case FILE_NOTIFY_ON_RELEASE: |
961 | retval = update_flag(CS_NOTIFY_ON_RELEASE, cs, buffer); | 982 | retval = update_flag(CS_NOTIFY_ON_RELEASE, cs, buffer); |
962 | break; | 983 | break; |
984 | case FILE_MEMORY_MIGRATE: | ||
985 | retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer); | ||
986 | break; | ||
963 | case FILE_TASKLIST: | 987 | case FILE_TASKLIST: |
964 | retval = attach_task(cs, buffer, &pathbuf); | 988 | retval = attach_task(cs, buffer, &pathbuf); |
965 | break; | 989 | break; |
@@ -1060,6 +1084,9 @@ static ssize_t cpuset_common_file_read(struct file *file, char __user *buf, | |||
1060 | case FILE_NOTIFY_ON_RELEASE: | 1084 | case FILE_NOTIFY_ON_RELEASE: |
1061 | *s++ = notify_on_release(cs) ? '1' : '0'; | 1085 | *s++ = notify_on_release(cs) ? '1' : '0'; |
1062 | break; | 1086 | break; |
1087 | case FILE_MEMORY_MIGRATE: | ||
1088 | *s++ = is_memory_migrate(cs) ? '1' : '0'; | ||
1089 | break; | ||
1063 | default: | 1090 | default: |
1064 | retval = -EINVAL; | 1091 | retval = -EINVAL; |
1065 | goto out; | 1092 | goto out; |
@@ -1408,6 +1435,11 @@ static struct cftype cft_notify_on_release = { | |||
1408 | .private = FILE_NOTIFY_ON_RELEASE, | 1435 | .private = FILE_NOTIFY_ON_RELEASE, |
1409 | }; | 1436 | }; |
1410 | 1437 | ||
1438 | static struct cftype cft_memory_migrate = { | ||
1439 | .name = "memory_migrate", | ||
1440 | .private = FILE_MEMORY_MIGRATE, | ||
1441 | }; | ||
1442 | |||
1411 | static int cpuset_populate_dir(struct dentry *cs_dentry) | 1443 | static int cpuset_populate_dir(struct dentry *cs_dentry) |
1412 | { | 1444 | { |
1413 | int err; | 1445 | int err; |
@@ -1422,6 +1454,8 @@ static int cpuset_populate_dir(struct dentry *cs_dentry) | |||
1422 | return err; | 1454 | return err; |
1423 | if ((err = cpuset_add_file(cs_dentry, &cft_notify_on_release)) < 0) | 1455 | if ((err = cpuset_add_file(cs_dentry, &cft_notify_on_release)) < 0) |
1424 | return err; | 1456 | return err; |
1457 | if ((err = cpuset_add_file(cs_dentry, &cft_memory_migrate)) < 0) | ||
1458 | return err; | ||
1425 | if ((err = cpuset_add_file(cs_dentry, &cft_tasks)) < 0) | 1459 | if ((err = cpuset_add_file(cs_dentry, &cft_tasks)) < 0) |
1426 | return err; | 1460 | return err; |
1427 | return 0; | 1461 | return 0; |