diff options
-rw-r--r-- | mm/migrate.c | 152 |
1 files changed, 86 insertions, 66 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index a4c29081ebce..11c6c56ec017 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -826,9 +826,11 @@ static struct page *new_page_node(struct page *p, unsigned long private, | |||
826 | * Move a set of pages as indicated in the pm array. The addr | 826 | * Move a set of pages as indicated in the pm array. The addr |
827 | * field must be set to the virtual address of the page to be moved | 827 | * field must be set to the virtual address of the page to be moved |
828 | * and the node number must contain a valid target node. | 828 | * and the node number must contain a valid target node. |
829 | * The pm array ends with node = MAX_NUMNODES. | ||
829 | */ | 830 | */ |
830 | static int do_move_pages(struct mm_struct *mm, struct page_to_node *pm, | 831 | static int do_move_page_to_node_array(struct mm_struct *mm, |
831 | int migrate_all) | 832 | struct page_to_node *pm, |
833 | int migrate_all) | ||
832 | { | 834 | { |
833 | int err; | 835 | int err; |
834 | struct page_to_node *pp; | 836 | struct page_to_node *pp; |
@@ -906,6 +908,81 @@ set_status: | |||
906 | } | 908 | } |
907 | 909 | ||
908 | /* | 910 | /* |
911 | * Migrate an array of page address onto an array of nodes and fill | ||
912 | * the corresponding array of status. | ||
913 | */ | ||
914 | static int do_pages_move(struct mm_struct *mm, struct task_struct *task, | ||
915 | unsigned long nr_pages, | ||
916 | const void __user * __user *pages, | ||
917 | const int __user *nodes, | ||
918 | int __user *status, int flags) | ||
919 | { | ||
920 | struct page_to_node *pm = NULL; | ||
921 | nodemask_t task_nodes; | ||
922 | int err = 0; | ||
923 | int i; | ||
924 | |||
925 | task_nodes = cpuset_mems_allowed(task); | ||
926 | |||
927 | /* Limit nr_pages so that the multiplication may not overflow */ | ||
928 | if (nr_pages >= ULONG_MAX / sizeof(struct page_to_node) - 1) { | ||
929 | err = -E2BIG; | ||
930 | goto out; | ||
931 | } | ||
932 | |||
933 | pm = vmalloc((nr_pages + 1) * sizeof(struct page_to_node)); | ||
934 | if (!pm) { | ||
935 | err = -ENOMEM; | ||
936 | goto out; | ||
937 | } | ||
938 | |||
939 | /* | ||
940 | * Get parameters from user space and initialize the pm | ||
941 | * array. Return various errors if the user did something wrong. | ||
942 | */ | ||
943 | for (i = 0; i < nr_pages; i++) { | ||
944 | const void __user *p; | ||
945 | |||
946 | err = -EFAULT; | ||
947 | if (get_user(p, pages + i)) | ||
948 | goto out_pm; | ||
949 | |||
950 | pm[i].addr = (unsigned long)p; | ||
951 | if (nodes) { | ||
952 | int node; | ||
953 | |||
954 | if (get_user(node, nodes + i)) | ||
955 | goto out_pm; | ||
956 | |||
957 | err = -ENODEV; | ||
958 | if (!node_state(node, N_HIGH_MEMORY)) | ||
959 | goto out_pm; | ||
960 | |||
961 | err = -EACCES; | ||
962 | if (!node_isset(node, task_nodes)) | ||
963 | goto out_pm; | ||
964 | |||
965 | pm[i].node = node; | ||
966 | } else | ||
967 | pm[i].node = 0; /* anything to not match MAX_NUMNODES */ | ||
968 | } | ||
969 | /* End marker */ | ||
970 | pm[nr_pages].node = MAX_NUMNODES; | ||
971 | |||
972 | err = do_move_page_to_node_array(mm, pm, flags & MPOL_MF_MOVE_ALL); | ||
973 | if (err >= 0) | ||
974 | /* Return status information */ | ||
975 | for (i = 0; i < nr_pages; i++) | ||
976 | if (put_user(pm[i].status, status + i)) | ||
977 | err = -EFAULT; | ||
978 | |||
979 | out_pm: | ||
980 | vfree(pm); | ||
981 | out: | ||
982 | return err; | ||
983 | } | ||
984 | |||
985 | /* | ||
909 | * Determine the nodes of an array of pages and store it in an array of status. | 986 | * Determine the nodes of an array of pages and store it in an array of status. |
910 | */ | 987 | */ |
911 | static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages, | 988 | static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages, |
@@ -963,12 +1040,9 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, | |||
963 | const int __user *nodes, | 1040 | const int __user *nodes, |
964 | int __user *status, int flags) | 1041 | int __user *status, int flags) |
965 | { | 1042 | { |
966 | int err = 0; | ||
967 | int i; | ||
968 | struct task_struct *task; | 1043 | struct task_struct *task; |
969 | nodemask_t task_nodes; | ||
970 | struct mm_struct *mm; | 1044 | struct mm_struct *mm; |
971 | struct page_to_node *pm = NULL; | 1045 | int err; |
972 | 1046 | ||
973 | /* Check flags */ | 1047 | /* Check flags */ |
974 | if (flags & ~(MPOL_MF_MOVE|MPOL_MF_MOVE_ALL)) | 1048 | if (flags & ~(MPOL_MF_MOVE|MPOL_MF_MOVE_ALL)) |
@@ -1000,75 +1074,21 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, | |||
1000 | (current->uid != task->suid) && (current->uid != task->uid) && | 1074 | (current->uid != task->suid) && (current->uid != task->uid) && |
1001 | !capable(CAP_SYS_NICE)) { | 1075 | !capable(CAP_SYS_NICE)) { |
1002 | err = -EPERM; | 1076 | err = -EPERM; |
1003 | goto out2; | 1077 | goto out; |
1004 | } | 1078 | } |
1005 | 1079 | ||
1006 | err = security_task_movememory(task); | 1080 | err = security_task_movememory(task); |
1007 | if (err) | 1081 | if (err) |
1008 | goto out2; | 1082 | goto out; |
1009 | 1083 | ||
1010 | if (!nodes) { | 1084 | if (nodes) { |
1085 | err = do_pages_move(mm, task, nr_pages, pages, nodes, status, | ||
1086 | flags); | ||
1087 | } else { | ||
1011 | err = do_pages_stat(mm, nr_pages, pages, status); | 1088 | err = do_pages_stat(mm, nr_pages, pages, status); |
1012 | goto out2; | ||
1013 | } | ||
1014 | |||
1015 | task_nodes = cpuset_mems_allowed(task); | ||
1016 | |||
1017 | /* Limit nr_pages so that the multiplication may not overflow */ | ||
1018 | if (nr_pages >= ULONG_MAX / sizeof(struct page_to_node) - 1) { | ||
1019 | err = -E2BIG; | ||
1020 | goto out2; | ||
1021 | } | 1089 | } |
1022 | 1090 | ||
1023 | pm = vmalloc((nr_pages + 1) * sizeof(struct page_to_node)); | ||
1024 | if (!pm) { | ||
1025 | err = -ENOMEM; | ||
1026 | goto out2; | ||
1027 | } | ||
1028 | |||
1029 | /* | ||
1030 | * Get parameters from user space and initialize the pm | ||
1031 | * array. Return various errors if the user did something wrong. | ||
1032 | */ | ||
1033 | for (i = 0; i < nr_pages; i++) { | ||
1034 | const void __user *p; | ||
1035 | |||
1036 | err = -EFAULT; | ||
1037 | if (get_user(p, pages + i)) | ||
1038 | goto out; | ||
1039 | |||
1040 | pm[i].addr = (unsigned long)p; | ||
1041 | if (nodes) { | ||
1042 | int node; | ||
1043 | |||
1044 | if (get_user(node, nodes + i)) | ||
1045 | goto out; | ||
1046 | |||
1047 | err = -ENODEV; | ||
1048 | if (!node_state(node, N_HIGH_MEMORY)) | ||
1049 | goto out; | ||
1050 | |||
1051 | err = -EACCES; | ||
1052 | if (!node_isset(node, task_nodes)) | ||
1053 | goto out; | ||
1054 | |||
1055 | pm[i].node = node; | ||
1056 | } else | ||
1057 | pm[i].node = 0; /* anything to not match MAX_NUMNODES */ | ||
1058 | } | ||
1059 | /* End marker */ | ||
1060 | pm[nr_pages].node = MAX_NUMNODES; | ||
1061 | |||
1062 | err = do_move_pages(mm, pm, flags & MPOL_MF_MOVE_ALL); | ||
1063 | if (err >= 0) | ||
1064 | /* Return status information */ | ||
1065 | for (i = 0; i < nr_pages; i++) | ||
1066 | if (put_user(pm[i].status, status + i)) | ||
1067 | err = -EFAULT; | ||
1068 | |||
1069 | out: | 1091 | out: |
1070 | vfree(pm); | ||
1071 | out2: | ||
1072 | mmput(mm); | 1092 | mmput(mm); |
1073 | return err; | 1093 | return err; |
1074 | } | 1094 | } |