mm/mempolicy: do not duplicate policy if it is not applicable for set_mempolicy_home_node
authorMichal Hocko <mhocko@suse.com>
Fri, 16 Dec 2022 19:45:37 +0000 (14:45 -0500)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 19 Jan 2023 01:12:41 +0000 (17:12 -0800)
set_mempolicy_home_node tries to duplicate a memory policy before checking
it whether it is applicable for the operation.  There is no real reason
for doing that and it might actually be a pointless memory allocation and
deallocation exercise for MPOL_INTERLEAVE.

Not a big problem but we can do better. Simply check the policy before
acting on it.

Link: https://lkml.kernel.org/r/20221216194537.238047-2-mathieu.desnoyers@efficios.com
Signed-off-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Feng Tang <feng.tang@intel.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Huang Ying <ying.huang@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/mempolicy.c

index 02c8a71..becf41e 100644 (file)
@@ -1489,7 +1489,7 @@ SYSCALL_DEFINE4(set_mempolicy_home_node, unsigned long, start, unsigned long, le
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
-       struct mempolicy *new;
+       struct mempolicy *new, *old;
        unsigned long vmstart;
        unsigned long vmend;
        unsigned long end;
@@ -1521,31 +1521,27 @@ SYSCALL_DEFINE4(set_mempolicy_home_node, unsigned long, start, unsigned long, le
                return 0;
        mmap_write_lock(mm);
        for_each_vma_range(vmi, vma, end) {
-               vmstart = max(start, vma->vm_start);
-               vmend   = min(end, vma->vm_end);
-               new = mpol_dup(vma_policy(vma));
-               if (IS_ERR(new)) {
-                       err = PTR_ERR(new);
-                       break;
-               }
-               /*
-                * Only update home node if there is an existing vma policy
-                */
-               if (!new)
-                       continue;
-
                /*
                 * If any vma in the range got policy other than MPOL_BIND
                 * or MPOL_PREFERRED_MANY we return error. We don't reset
                 * the home node for vmas we already updated before.
                 */
-               if (new->mode != MPOL_BIND && new->mode != MPOL_PREFERRED_MANY) {
-                       mpol_put(new);
+               old = vma_policy(vma);
+               if (!old)
+                       continue;
+               if (old->mode != MPOL_BIND && old->mode != MPOL_PREFERRED_MANY) {
                        err = -EOPNOTSUPP;
                        break;
                }
+               new = mpol_dup(old);
+               if (IS_ERR(new)) {
+                       err = PTR_ERR(new);
+                       break;
+               }
 
                new->home_node = home_node;
+               vmstart = max(start, vma->vm_start);
+               vmend   = min(end, vma->vm_end);
                err = mbind_range(mm, vmstart, vmend, new);
                mpol_put(new);
                if (err)