]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm: mprotect: convert to folio_can_map_prot_numa()
authorKefeng Wang <wangkefeng.wang@huawei.com>
Thu, 23 Oct 2025 11:37:36 +0000 (19:37 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 17 Nov 2025 01:28:03 +0000 (17:28 -0800)
The prot_numa_skip() naming is not good since it updates the folio access
time except checking whether to skip prot NUMA, so rename it to
folio_can_map_prot_numa(), and cleanup it a bit, remove ret by directly
return value instead of goto style.

Adding a new helper vma_is_single_threaded_private() to check whether it's
a single threaded private VMA, and make folio_can_map_prot_numa() a
non-static function so that they could be reused in change_huge_pmd(),
since folio_can_map_prot_numa() will be shared in different paths, let's
move it near change_prot_numa() in mempolicy.c.

Link: https://lkml.kernel.org/r/20251023113737.3572790-4-wangkefeng.wang@huawei.com
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Acked-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Sidhartha Kumar <sidhartha.kumar@oracle.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/internal.h
mm/mempolicy.c
mm/mprotect.c

index e623c81033588e27b173dfd07066c5d456ed557b..56a9a714709ac69a86346f47d021df086eca9bb9 100644 (file)
@@ -1378,6 +1378,26 @@ void vunmap_range_noflush(unsigned long start, unsigned long end);
 
 void __vunmap_range_noflush(unsigned long start, unsigned long end);
 
+static inline bool vma_is_single_threaded_private(struct vm_area_struct *vma)
+{
+       if (vma->vm_flags & VM_SHARED)
+               return false;
+
+       return atomic_read(&vma->vm_mm->mm_users) == 1;
+}
+
+#ifdef CONFIG_NUMA_BALANCING
+bool folio_can_map_prot_numa(struct folio *folio, struct vm_area_struct *vma,
+               bool is_private_single_threaded);
+
+#else
+static inline bool folio_can_map_prot_numa(struct folio *folio,
+               struct vm_area_struct *vma, bool is_private_single_threaded)
+{
+       return false;
+}
+#endif
+
 int numa_migrate_check(struct folio *folio, struct vm_fault *vmf,
                      unsigned long addr, int *flags, bool writable,
                      int *last_cpupid);
index eb83cff7db8c35708296e5216e07783dc1bcb9b6..7ae3f5e2dee6364a3dcd4f1fe34f5e98f12697c1 100644 (file)
@@ -85,6 +85,7 @@
 #include <linux/sched.h>
 #include <linux/sched/mm.h>
 #include <linux/sched/numa_balancing.h>
+#include <linux/sched/sysctl.h>
 #include <linux/sched/task.h>
 #include <linux/nodemask.h>
 #include <linux/cpuset.h>
 #include <linux/swap.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
+#include <linux/memory-tiers.h>
 #include <linux/migrate.h>
 #include <linux/ksm.h>
 #include <linux/rmap.h>
@@ -803,6 +805,65 @@ unlock:
 }
 
 #ifdef CONFIG_NUMA_BALANCING
+/**
+ * folio_can_map_prot_numa() - check whether the folio can map prot numa
+ * @folio: The folio whose mapping considered for being made NUMA hintable
+ * @vma: The VMA that the folio belongs to.
+ * @is_private_single_threaded: Is this a single-threaded private VMA or not
+ *
+ * This function checks to see if the folio actually indicates that
+ * we need to make the mapping one which causes a NUMA hinting fault,
+ * as there are cases where it's simply unnecessary, and the folio's
+ * access time is adjusted for memory tiering if prot numa needed.
+ *
+ * Return: True if the mapping of the folio needs to be changed, false otherwise.
+ */
+bool folio_can_map_prot_numa(struct folio *folio, struct vm_area_struct *vma,
+               bool is_private_single_threaded)
+{
+       int nid;
+
+       if (!folio || folio_is_zone_device(folio) || folio_test_ksm(folio))
+               return false;
+
+       /* Also skip shared copy-on-write folios */
+       if (is_cow_mapping(vma->vm_flags) && folio_maybe_mapped_shared(folio))
+               return false;
+
+       /* Folios are pinned and can't be migrated */
+       if (folio_maybe_dma_pinned(folio))
+               return false;
+
+       /*
+        * While migration can move some dirty folios,
+        * it cannot move them all from MIGRATE_ASYNC
+        * context.
+        */
+       if (folio_is_file_lru(folio) && folio_test_dirty(folio))
+               return false;
+
+       /*
+        * Don't mess with PTEs if folio is already on the node
+        * a single-threaded process is running on.
+        */
+       nid = folio_nid(folio);
+       if (is_private_single_threaded && (nid == numa_node_id()))
+               return false;
+
+       /*
+        * Skip scanning top tier node if normal numa
+        * balancing is disabled
+        */
+       if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_NORMAL) &&
+           node_is_toptier(nid))
+               return false;
+
+       if (folio_use_access_time(folio))
+               folio_xchg_access_time(folio, jiffies_to_msecs(jiffies));
+
+       return true;
+}
+
 /*
  * This is used to mark a range of virtual addresses to be inaccessible.
  * These are later cleared by a NUMA hinting fault. Depending on these
index 6236d120c8e6d5779db2b5caef084216570c54fc..ab4e06cd9a6977fb791fabd65e0636612ebc9e01 100644 (file)
@@ -29,9 +29,7 @@
 #include <linux/uaccess.h>
 #include <linux/mm_inline.h>
 #include <linux/pgtable.h>
-#include <linux/sched/sysctl.h>
 #include <linux/userfaultfd_k.h>
-#include <linux/memory-tiers.h>
 #include <uapi/linux/mman.h>
 #include <asm/cacheflush.h>
 #include <asm/mmu_context.h>
@@ -118,60 +116,6 @@ static int mprotect_folio_pte_batch(struct folio *folio, pte_t *ptep,
        return folio_pte_batch_flags(folio, NULL, ptep, &pte, max_nr_ptes, flags);
 }
 
-static bool prot_numa_skip(struct vm_area_struct *vma, int target_node,
-               struct folio *folio)
-{
-       bool ret = true;
-       bool toptier;
-       int nid;
-
-       if (!folio)
-               goto skip;
-
-       if (folio_is_zone_device(folio) || folio_test_ksm(folio))
-               goto skip;
-
-       /* Also skip shared copy-on-write folios */
-       if (is_cow_mapping(vma->vm_flags) && folio_maybe_mapped_shared(folio))
-               goto skip;
-
-       /* Folios are pinned and can't be migrated */
-       if (folio_maybe_dma_pinned(folio))
-               goto skip;
-
-       /*
-        * While migration can move some dirty pages,
-        * it cannot move them all from MIGRATE_ASYNC
-        * context.
-        */
-       if (folio_is_file_lru(folio) && folio_test_dirty(folio))
-               goto skip;
-
-       /*
-        * Don't mess with PTEs if page is already on the node
-        * a single-threaded process is running on.
-        */
-       nid = folio_nid(folio);
-       if (target_node == nid)
-               goto skip;
-
-       toptier = node_is_toptier(nid);
-
-       /*
-        * Skip scanning top tier node if normal numa
-        * balancing is disabled
-        */
-       if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_NORMAL) && toptier)
-               goto skip;
-
-       ret = false;
-       if (folio_use_access_time(folio))
-               folio_xchg_access_time(folio, jiffies_to_msecs(jiffies));
-
-skip:
-       return ret;
-}
-
 /* Set nr_ptes number of ptes, starting from idx */
 static void prot_commit_flush_ptes(struct vm_area_struct *vma, unsigned long addr,
                pte_t *ptep, pte_t oldpte, pte_t ptent, int nr_ptes,
@@ -274,7 +218,7 @@ static long change_pte_range(struct mmu_gather *tlb,
        pte_t *pte, oldpte;
        spinlock_t *ptl;
        long pages = 0;
-       int target_node = NUMA_NO_NODE;
+       bool is_private_single_threaded;
        bool prot_numa = cp_flags & MM_CP_PROT_NUMA;
        bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
        bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE;
@@ -285,10 +229,8 @@ static long change_pte_range(struct mmu_gather *tlb,
        if (!pte)
                return -EAGAIN;
 
-       /* Get target node for single threaded private VMAs */
-       if (prot_numa && !(vma->vm_flags & VM_SHARED) &&
-           atomic_read(&vma->vm_mm->mm_users) == 1)
-               target_node = numa_node_id();
+       if (prot_numa)
+               is_private_single_threaded = vma_is_single_threaded_private(vma);
 
        flush_tlb_batched_pending(vma->vm_mm);
        arch_enter_lazy_mmu_mode();
@@ -315,7 +257,8 @@ static long change_pte_range(struct mmu_gather *tlb,
                         * pages. See similar comment in change_huge_pmd.
                         */
                        if (prot_numa &&
-                           prot_numa_skip(vma, target_node, folio)) {
+                           !folio_can_map_prot_numa(folio, vma,
+                                               is_private_single_threaded)) {
 
                                /* determine batch to skip */
                                nr_ptes = mprotect_folio_pte_batch(folio,