]> 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 a2af6d58a68fc087feddf1181ecb511bde86cecd..02377f289a7fe42d3e88ebaf68137d356a1a9473 100644 (file)
@@ -85,6 +85,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/compat.h>
+#include <linux/ptrace.h>
 #include <linux/swap.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
@@ -1262,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;
 
@@ -1278,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) {
@@ -1297,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;
@@ -1365,7 +1383,6 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode,
                const unsigned long __user *, old_nodes,
                const unsigned long __user *, new_nodes)
 {
-       const struct cred *cred = current_cred(), *tcred;
        struct mm_struct *mm = NULL;
        struct task_struct *task;
        nodemask_t task_nodes;
@@ -1401,15 +1418,10 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode,
        err = -EINVAL;
 
        /*
-        * Check if this process has the right to modify the specified
-        * process. The right exists if the process has administrative
-        * capabilities, superuser privileges or the same
-        * userid as the target process.
+        * Check if this process has the right to modify the specified process.
+        * Use the regular "ptrace_may_access()" checks.
         */
-       tcred = __task_cred(task);
-       if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
-           !uid_eq(cred->uid,  tcred->suid) && !uid_eq(cred->uid,  tcred->uid) &&
-           !capable(CAP_SYS_NICE)) {
+       if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
                rcu_read_unlock();
                err = -EPERM;
                goto out_put;
@@ -1423,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)
@@ -1920,6 +1936,9 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
        struct page *page;
 
        page = __alloc_pages(gfp, order, nid);
+       /* skip NUMA_INTERLEAVE_HIT counter update if numa stats is disabled */
+       if (!static_branch_likely(&vm_numa_stat_key))
+               return page;
        if (page && page_to_nid(page) == nid) {
                preempt_disable();
                __inc_numa_state(page_zone(page), NUMA_INTERLEAVE_HIT);
@@ -2107,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();