]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - mm/mempolicy.c
drm/radeon: prefer lower reference dividers
[mirror_ubuntu-bionic-kernel.git] / mm / mempolicy.c
index 4ce44d3ff03da6a6f09a9b92c9bb0750aaf3b7a4..02377f289a7fe42d3e88ebaf68137d356a1a9473 100644 (file)
@@ -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,19 @@ 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 +1305,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 +1435,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)
@@ -2105,6 +2126,9 @@ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
        case MPOL_INTERLEAVE:
                return !!nodes_equal(a->v.nodes, b->v.nodes);
        case MPOL_PREFERRED:
+               /* a's ->flags is the same as b's */
+               if (a->flags & MPOL_F_LOCAL)
+                       return true;
                return a->v.preferred_node == b->v.preferred_node;
        default:
                BUG();