Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
[linux-2.6-block.git] / mm / mempolicy.c
index 4ce44d3ff03da6a6f09a9b92c9bb0750aaf3b7a4..d879f1d8a44ade626a5ed91aa3973068f16d8bc2 100644 (file)
@@ -1121,8 +1121,8 @@ static struct page *new_page(struct page *page, unsigned long start, int **x)
        }
 
        if (PageHuge(page)) {
-               BUG_ON(!vma);
-               return alloc_huge_page_noerr(vma, address, 1);
+               return alloc_huge_page_vma(page_hstate(compound_head(page)),
+                               vma, address);
        } else if (thp_migration_supported() && PageTransHuge(page)) {
                struct page *thp;
 
@@ -1263,6 +1263,7 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
                     unsigned long maxnode)
 {
        unsigned long k;
+       unsigned long t;
        unsigned long nlongs;
        unsigned long endmask;
 
@@ -1279,13 +1280,17 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
        else
                endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1;
 
-       /* When the user specified more nodes than supported just check
-          if the non supported part is all zero. */
+       /*
+        * When the user specified more nodes than supported just check
+        * if the non supported part is all zero.
+        *
+        * If maxnode have more longs than MAX_NUMNODES, check
+        * the bits in that area first. And then go through to
+        * check the rest bits which equal or bigger than MAX_NUMNODES.
+        * Otherwise, just check bits [MAX_NUMNODES, maxnode).
+        */
        if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) {
-               if (nlongs > PAGE_SIZE/sizeof(long))
-                       return -EINVAL;
                for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) {
-                       unsigned long t;
                        if (get_user(t, nmask + k))
                                return -EFAULT;
                        if (k == nlongs - 1) {
@@ -1298,6 +1303,16 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
                endmask = ~0UL;
        }
 
+       if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) {
+               unsigned long valid_mask = endmask;
+
+               valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1);
+               if (get_user(t, nmask + nlongs - 1))
+                       return -EFAULT;
+               if (t & valid_mask)
+                       return -EINVAL;
+       }
+
        if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long)))
                return -EFAULT;
        nodes_addr(*nodes)[nlongs-1] &= endmask;
@@ -1418,10 +1433,14 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode,
                goto out_put;
        }
 
-       if (!nodes_subset(*new, node_states[N_MEMORY])) {
-               err = -EINVAL;
+       task_nodes = cpuset_mems_allowed(current);
+       nodes_and(*new, *new, task_nodes);
+       if (nodes_empty(*new))
+               goto out_put;
+
+       nodes_and(*new, *new, node_states[N_MEMORY]);
+       if (nodes_empty(*new))
                goto out_put;
-       }
 
        err = security_task_movememory(task);
        if (err)