[RFC PATCH 6/7] mm: Make /proc/pid/numa_maps use the new generic pagewalk API

Oscar Salvador
2026-04-12T17:43:12Z

Have /proc/pid/numa_maps make use of the new generic API, and remove
the code which was using the old one

Signed-off-by: Oscar Salvador <osalvador@suse.de>
---
fs/proc/task_mmu.c | 136 +++++++++++----------------------------------
1 file changed, 32 insertions(+), 104 deletions(-)

diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index afbcdb11ad80..776e7a6baf00 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -3048,108 +3048,6 @@ static struct page *can_gather_numa_stats(pte_t pte, struct vm_area_struct *vma,
return page;
}

-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static struct page *can_gather_numa_stats_pmd(pmd_t pmd,
- struct vm_area_struct *vma,
- unsigned long addr)
-{
- struct page *page;
- int nid;
-
- if (!pmd_present(pmd))
- return NULL;
-
- page = vm_normal_page_pmd(vma, addr, pmd);
- if (!page)
- return NULL;
-
- if (PageReserved(page))
- return NULL;
-
- nid = page_to_nid(page);
- if (!node_isset(nid, node_states[N_MEMORY]))
- return NULL;
-
- return page;
-}
-#endif
-
-static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
- unsigned long end, struct mm_walk *walk)
-{
- struct numa_maps *md = walk->private;
- struct vm_area_struct *vma = walk->vma;
- spinlock_t *ptl;
- pte_t *orig_pte;
- pte_t *pte;
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- ptl = pmd_trans_huge_lock(pmd, vma);
- if (ptl) {
- struct page *page;
-
- page = can_gather_numa_stats_pmd(*pmd, vma, addr);
- if (page)
- gather_stats(page, md, pmd_dirty(*pmd),
- HPAGE_PMD_SIZE/PAGE_SIZE);
- spin_unlock(ptl);
- return 0;
- }
-#endif
- orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
- if (!pte) {
- walk->action = ACTION_AGAIN;
- return 0;
- }
- do {
- pte_t ptent = ptep_get(pte);
- struct page *page = can_gather_numa_stats(ptent, vma, addr);
- if (!page)
- continue;
- gather_stats(page, md, pte_dirty(ptent), 1);
-
- } while (pte++, addr += PAGE_SIZE, addr != end);
- pte_unmap_unlock(orig_pte, ptl);
- cond_resched();
- return 0;
-}
-#ifdef CONFIG_HUGETLB_PAGE
-static int gather_hugetlb_stats(pte_t *pte, unsigned long hmask,
- unsigned long addr, unsigned long end, struct mm_walk *walk)
-{
- pte_t huge_pte;
- struct numa_maps *md;
- struct page *page;
- spinlock_t *ptl;
-
- ptl = huge_pte_lock(hstate_vma(walk->vma), walk->mm, pte);
- huge_pte = huge_ptep_get(walk->mm, addr, pte);
- if (!pte_present(huge_pte))
- goto out;
-
- page = pte_page(huge_pte);
-
- md = walk->private;
- gather_stats(page, md, pte_dirty(huge_pte), 1);
-out:
- spin_unlock(ptl);
- return 0;
-}
-
-#else
-static int gather_hugetlb_stats(pte_t *pte, unsigned long hmask,
- unsigned long addr, unsigned long end, struct mm_walk *walk)
-{
- return 0;
-}
-#endif
-
-static const struct mm_walk_ops show_numa_ops = {
- .hugetlb_entry = gather_hugetlb_stats,
- .pmd_entry = gather_pte_stats,
- .walk_lock = PGWALK_RDLOCK,
-};
-
/*
* Display pages allocated per node and memory policy via /proc.
*/
@@ -3161,9 +3059,15 @@ static int show_numa_map(struct seq_file *m, void *v)
struct numa_maps *md = &numa_priv->md;
struct file *file = vma->vm_file;
struct mm_struct *mm = vma->vm_mm;
+ struct pt_range_walk ptw = {
+ .mm = mm
+ };
+ enum pt_range_walk_type type;
+ pt_type_flags_t flags;
char buffer[64];
struct mempolicy *pol;
pgoff_t ilx;
+ int nr_pages;
int nid;

if (!mm)
@@ -3194,8 +3098,32 @@ static int show_numa_map(struct seq_file *m, void *v)
if (is_vm_hugetlb_page(vma))
seq_puts(m, " huge");

- /* mmap_lock is held by m_start */
- walk_page_vma(vma, &show_numa_ops, md);
+ flags = PT_TYPE_FOLIO;
+ type = pt_range_walk_start(&ptw, vma, vma->vm_start, vma->vm_end, flags);
+ while (type != PTW_DONE) {
+
+ if (!ptw.folio || !ptw.page || PageReserved(ptw.page))
+ goto not_found;
+
+ nid = page_to_nid(ptw.page);
+ if (!node_isset(nid, node_states[N_MEMORY]))
+ goto not_found;
+
+ if (is_vm_hugetlb_page(vma))
+ /*
+ * As opposed to THP, HugeTLB counts the entire huge
+ * page as one unit size.
+ */
+ nr_pages = ptw.nr_entries;
+ else
+ nr_pages = ptw.size / PAGE_SIZE;
+
+ gather_stats(ptw.page, md, ptw.dirty, nr_pages);
+not_found:
+ type = pt_range_walk_next(&ptw, vma, vma->vm_start, vma->vm_end, flags);
+
+ }
+ pt_range_walk_done(&ptw);

if (!md->pages)
goto out;
--
2.35.3