mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 11:06:41 -05:00
mm: mprotect: convert to folio_can_map_prot_numa()
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>
This commit is contained in:
committed by
Andrew Morton
parent
6e97624dac
commit
ca43034cdb
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
@@ -99,6 +100,7 @@
|
||||
#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 @@ static int queue_folios_hugetlb(pte_t *pte, unsigned long hmask,
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user