aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/migrate.c152
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 */
830static int do_move_pages(struct mm_struct *mm, struct page_to_node *pm, 831static 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 */
914static 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
979out_pm:
980 vfree(pm);
981out:
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 */
911static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages, 988static 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
1069out: 1091out:
1070 vfree(pm);
1071out2:
1072 mmput(mm); 1092 mmput(mm);
1073 return err; 1093 return err;
1074} 1094}