linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] mm/debug_vm_pgtable: Enhancements
@ 2021-07-06  6:17 Gavin Shan
  2021-07-06  6:17 ` [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug Gavin Shan
                   ` (12 more replies)
  0 siblings, 13 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

There are couple of issues with current implementations and this series
tries to resolve the issues:

  (a) All needed information are scattered in variables, passed to various
      test functions. The code is organized in pretty much relaxed fashion.

  (b) The page isn't allocated from buddy during page table entry modifying
      tests. The page can be invalid, conflicting to the implementations
      of set_{pud, pmd, pte}_at() on ARM64. The target page is accessed
      so that the iCache can be flushed when execution permission is given
      on ARM64. Besides, the target page can be unmapped and access to
      it causes kernel crash.

"struct vm_pgtable_debug" is introduced to address issue (a). For issue
(b), the used page is allocated from buddy in page table entry modifying
tests. The corresponding tets will be skipped if we fail to allocate the
(huge) page. For other test cases, the original page around to kernel
symbol (@start_kernel) is still used.

The patches are organized as below. PATCH[2-10] could be combined to one
patch, but it will make the review harder:

  PATCH[1] introduces "struct vm_pgtable_debug" as place holder of all
           needed information. With it, the old and new implementation
           can coexist.
  PATCH[2-10] uses "struct vm_pgtable_debug" in various test functions.
  PATCH[11] removes the old implementation.
  PATCH[12] fixes the issue of corrupted page flag for ARM64


Gavin Shan (12):
  mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug
  mm/debug_vm_pgtable: Use struct vm_pgtable_debug in basic tests
  mm/debug_vm_pgtable: Use struct vm_pgtable_debug in leaf and savewrite
    tests
  mm/debug_vm_pgtable: Use struct vm_pgtable_debug in protnone and
    devmap tests
  mm/vm_debug_pgtable: Use struct vm_pgtable_debug in soft_dirty and
    swap tests
  mm/debug_vm_pgtable: Use struct vm_pgtable_debug in migration and thp
    tests
  mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PTE modifying
    tests
  mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PMD modifying
    tests
  mm/vm_debug_pgtable: Use struct vm_pgtable_debug in PUD modifying
    tests
  mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PGD and P4D
    modifying tests
  mm/debug_vm_pgtable: Remove unused code
  mm/debug_vm_pgtable: Fix corrupted page flag

 mm/debug_vm_pgtable.c | 875 ++++++++++++++++++++++++------------------
 1 file changed, 500 insertions(+), 375 deletions(-)

-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-14  6:24   ` Anshuman Khandual
  2021-07-06  6:17 ` [PATCH 02/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in basic tests Gavin Shan
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

In debug_vm_pgtable(), there are many local variables introduced
to track the needed information and they are passed to the functions
for various test cases. It'd better to introduce a struct as place
holder for these information. With it, what the functions for various
test cases need is the struct, to simplify the code. It makes the code
easier to be maintained.

Besides, set_pte_at() could access the data on the corresponding pages.
So the test cases using set_pte_at() should have the pages allocated
from buddy. Otherwise, we're acceessing pages that aren't owned by us.
This causes issues like page flag corruption. So we need the allocated
pages for these tests where set_pte_at() is used. The struct is introduced
so that the old and new implementation can coexist so that the patches
can be organized in a easy way.

This introduces "struct vm_pgtable_debug" for above purposes. The struct
is initialized and destroyed, but the information in the struct isn't
used yet. They will be used in subsequent patches.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 210 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 209 insertions(+), 1 deletion(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 1c922691aa61..225e2ea4d72f 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -58,6 +58,36 @@
 #define RANDOM_ORVALUE (GENMASK(BITS_PER_LONG - 1, 0) & ~ARCH_SKIP_MASK)
 #define RANDOM_NZVALUE	GENMASK(7, 0)
 
+struct vm_pgtable_debug {
+	struct mm_struct	*mm;
+	struct vm_area_struct	*vma;
+
+	pgd_t			*pgdp;
+	p4d_t			*p4dp;
+	pud_t			*pudp;
+	pmd_t			*pmdp;
+	pte_t			*ptep;
+
+	p4d_t			*start_p4dp;
+	pud_t			*start_pudp;
+	pmd_t			*start_pmdp;
+	pgtable_t		start_ptep;
+
+	unsigned long		vaddr;
+	pgprot_t		page_prot;
+	pgprot_t		page_prot_none;
+
+	unsigned long		pud_pfn;
+	unsigned long		pmd_pfn;
+	unsigned long		pte_pfn;
+
+	unsigned long		fixed_pgd_pfn;
+	unsigned long		fixed_p4d_pfn;
+	unsigned long		fixed_pud_pfn;
+	unsigned long		fixed_pmd_pfn;
+	unsigned long		fixed_pte_pfn;
+};
+
 static void __init pte_basic_tests(unsigned long pfn, int idx)
 {
 	pgprot_t prot = protection_map[idx];
@@ -955,8 +985,180 @@ static unsigned long __init get_random_vaddr(void)
 	return random_vaddr;
 }
 
+static void __init free_mem(struct vm_pgtable_debug *debug)
+{
+	struct page *page = NULL;
+	int order = 0;
+
+	/* Free (huge) page */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
+	if (has_transparent_hugepage() &&
+	    debug->pud_pfn != ULONG_MAX) {
+		page = pfn_to_page(debug->pud_pfn);
+		order = HPAGE_PUD_SHIFT - PAGE_SHIFT;
+	}
+#endif
+
+	if (has_transparent_hugepage() &&
+	    debug->pmd_pfn != ULONG_MAX && !page) {
+		page = pfn_to_page(debug->pmd_pfn);
+		order = HPAGE_PMD_ORDER;
+	}
+#endif
+
+	if (debug->pte_pfn != ULONG_MAX && !page) {
+		page = pfn_to_page(debug->pte_pfn);
+		order = 0;
+	}
+
+	if (page)
+		__free_pages(page, order);
+
+	/* Free page table */
+	if (debug->start_ptep) {
+		pte_free(debug->mm, debug->start_ptep);
+		mm_dec_nr_ptes(debug->mm);
+	}
+
+	if (debug->start_pmdp) {
+		pmd_free(debug->mm, debug->start_pmdp);
+		mm_dec_nr_pmds(debug->mm);
+	}
+
+	if (debug->start_pudp) {
+		pud_free(debug->mm, debug->start_pudp);
+		mm_dec_nr_puds(debug->mm);
+	}
+
+	if (debug->start_p4dp)
+		p4d_free(debug->mm, debug->p4dp);
+
+	/* Free vma and mm struct */
+	if (debug->vma)
+		vm_area_free(debug->vma);
+	if (debug->mm)
+		mmdrop(debug->mm);
+}
+
+static int __init alloc_mem(struct vm_pgtable_debug *debug)
+{
+	struct page *page = NULL;
+	phys_addr_t phys;
+	int ret = 0;
+
+	/* Initialize the debugging data */
+	debug->mm             = NULL;
+	debug->vma            = NULL;
+	debug->pgdp           = NULL;
+	debug->p4dp           = NULL;
+	debug->pudp           = NULL;
+	debug->pmdp           = NULL;
+	debug->ptep           = NULL;
+	debug->start_p4dp     = NULL;
+	debug->start_pudp     = NULL;
+	debug->start_pmdp     = NULL;
+	debug->start_ptep     = NULL;
+	debug->vaddr          = 0UL;
+	debug->page_prot      = vm_get_page_prot(VM_READ | VM_WRITE | VM_EXEC);
+	debug->page_prot_none = __P000;
+	debug->pud_pfn        = ULONG_MAX;
+	debug->pmd_pfn        = ULONG_MAX;
+	debug->pte_pfn        = ULONG_MAX;
+	debug->fixed_pgd_pfn  = ULONG_MAX;
+	debug->fixed_p4d_pfn  = ULONG_MAX;
+	debug->fixed_pud_pfn  = ULONG_MAX;
+	debug->fixed_pmd_pfn  = ULONG_MAX;
+	debug->fixed_pte_pfn  = ULONG_MAX;
+
+	/* Allocate mm and vma */
+	debug->mm = mm_alloc();
+	if (!debug->mm) {
+		pr_warn("Failed to allocate mm struct\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	debug->vma = vm_area_alloc(debug->mm);
+	if (!debug->vma) {
+		pr_warn("Failed to allocate vma\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	/* Figure out the virtual address and allocate page table entries */
+	debug->vaddr = get_random_vaddr();
+	debug->pgdp = pgd_offset(debug->mm, debug->vaddr);
+	debug->p4dp = p4d_alloc(debug->mm, debug->pgdp, debug->vaddr);
+	debug->pudp = debug->p4dp ?
+		      pud_alloc(debug->mm, debug->p4dp, debug->vaddr) : NULL;
+	debug->pmdp = debug->pudp ?
+		      pmd_alloc(debug->mm, debug->pudp, debug->vaddr) : NULL;
+	debug->ptep = debug->pmdp ?
+		      pte_alloc_map(debug->mm, debug->pmdp, debug->vaddr) : NULL;
+	if (!debug->ptep) {
+		pr_warn("Failed to allocate page table\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	/*
+	 * The above page table entries will be modified. Lets save the
+	 * page table entries so that they can be released when the tests
+	 * are completed.
+	 */
+	debug->start_p4dp = p4d_offset(debug->pgdp, 0UL);
+	debug->start_pudp = pud_offset(debug->p4dp, 0UL);
+	debug->start_pmdp = pmd_offset(debug->pudp, 0UL);
+	debug->start_ptep = pmd_pgtable(*(debug->pmdp));
+
+	/*
+	 * Figure out the fixed addresses, which are all around the kernel
+	 * symbol (@start_kernel). The corresponding PFNs might be invalid,
+	 * but it's fine as the following tests won't access the pages.
+	 */
+	phys = __pa_symbol(&start_kernel);
+	debug->fixed_pgd_pfn = __phys_to_pfn(phys & PGDIR_MASK);
+	debug->fixed_p4d_pfn = __phys_to_pfn(phys & P4D_MASK);
+	debug->fixed_pud_pfn = __phys_to_pfn(phys & PUD_MASK);
+	debug->fixed_pmd_pfn = __phys_to_pfn(phys & PMD_MASK);
+	debug->fixed_pte_pfn = __phys_to_pfn(phys & PAGE_MASK);
+
+	/*
+	 * Allocate (huge) pages because some of the tests need to access
+	 * the data in the pages. The corresponding tests will be skipped
+	 * if we fail to allocate (huge) pages.
+	 */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
+	if (has_transparent_hugepage()) {
+		page = alloc_pages(GFP_KERNEL, HPAGE_PUD_SHIFT - PAGE_SHIFT);
+		if (page)
+			debug->pud_pfn = page_to_pfn(page);
+	}
+#endif
+
+	if (has_transparent_hugepage()) {
+		page = page ? page : alloc_pages(GFP_KERNEL, HPAGE_PMD_ORDER);
+		if (page)
+			debug->pmd_pfn = page_to_pfn(page);
+	}
+#endif
+
+	page = page ? page : alloc_pages(GFP_KERNEL, 0);
+	if (page)
+		debug->pte_pfn = page_to_pfn(page);
+
+	return 0;
+
+error:
+	free_mem(debug);
+	return ret;
+}
+
 static int __init debug_vm_pgtable(void)
 {
+	struct vm_pgtable_debug debug;
 	struct vm_area_struct *vma;
 	struct mm_struct *mm;
 	pgd_t *pgdp;
@@ -970,9 +1172,13 @@ static int __init debug_vm_pgtable(void)
 	unsigned long vaddr, pte_aligned, pmd_aligned;
 	unsigned long pud_aligned, p4d_aligned, pgd_aligned;
 	spinlock_t *ptl = NULL;
-	int idx;
+	int idx, ret;
 
 	pr_info("Validating architecture page table helpers\n");
+	ret = alloc_mem(&debug);
+	if (ret)
+		return ret;
+
 	prot = vm_get_page_prot(VMFLAGS);
 	vaddr = get_random_vaddr();
 	mm = mm_alloc();
@@ -1127,6 +1333,8 @@ static int __init debug_vm_pgtable(void)
 	mm_dec_nr_pmds(mm);
 	mm_dec_nr_ptes(mm);
 	mmdrop(mm);
+
+	free_mem(&debug);
 	return 0;
 }
 late_initcall(debug_vm_pgtable);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 02/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in basic tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
  2021-07-06  6:17 ` [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 03/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in leaf and savewrite tests Gavin Shan
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in the basic test functions. There
are more cleanups applied:

   * Move hugetlb_basic_tests() so that the basic tests are treated
     as a bundle.

   * Drop parameters to {pgd, p4d}_basic_tests() as they're never
     used.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 47 +++++++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 24 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 225e2ea4d72f..759f27e1046e 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -88,10 +88,10 @@ struct vm_pgtable_debug {
 	unsigned long		fixed_pte_pfn;
 };
 
-static void __init pte_basic_tests(unsigned long pfn, int idx)
+static void __init pte_basic_tests(struct vm_pgtable_debug *debug, int idx)
 {
 	pgprot_t prot = protection_map[idx];
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte = pfn_pte(debug->fixed_pte_pfn, prot);
 	unsigned long val = idx, *ptr = &val;
 
 	pr_debug("Validating PTE basic (%pGv)\n", ptr);
@@ -173,7 +173,7 @@ static void __init pte_savedwrite_tests(unsigned long pfn, pgprot_t prot)
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static void __init pmd_basic_tests(unsigned long pfn, int idx)
+static void __init pmd_basic_tests(struct vm_pgtable_debug *debug, int idx)
 {
 	pgprot_t prot = protection_map[idx];
 	unsigned long val = idx, *ptr = &val;
@@ -183,7 +183,7 @@ static void __init pmd_basic_tests(unsigned long pfn, int idx)
 		return;
 
 	pr_debug("Validating PMD basic (%pGv)\n", ptr);
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, prot);
 
 	/*
 	 * This test needs to be executed after the given page table entry
@@ -295,7 +295,7 @@ static void __init pmd_savedwrite_tests(unsigned long pfn, pgprot_t prot)
 }
 
 #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
-static void __init pud_basic_tests(struct mm_struct *mm, unsigned long pfn, int idx)
+static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx)
 {
 	pgprot_t prot = protection_map[idx];
 	unsigned long val = idx, *ptr = &val;
@@ -305,7 +305,7 @@ static void __init pud_basic_tests(struct mm_struct *mm, unsigned long pfn, int
 		return;
 
 	pr_debug("Validating PUD basic (%pGv)\n", ptr);
-	pud = pfn_pud(pfn, prot);
+	pud = pfn_pud(debug->fixed_pud_pfn, prot);
 
 	/*
 	 * This test needs to be executed after the given page table entry
@@ -326,7 +326,7 @@ static void __init pud_basic_tests(struct mm_struct *mm, unsigned long pfn, int
 	WARN_ON(pud_dirty(pud_wrprotect(pud_mkclean(pud))));
 	WARN_ON(!pud_dirty(pud_wrprotect(pud_mkdirty(pud))));
 
-	if (mm_pmd_folded(mm))
+	if (mm_pmd_folded(debug->mm))
 		return;
 
 	/*
@@ -403,7 +403,7 @@ static void __init pud_leaf_tests(unsigned long pfn, pgprot_t prot)
 	WARN_ON(!pud_leaf(pud));
 }
 #else  /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
-static void __init pud_basic_tests(struct mm_struct *mm, unsigned long pfn, int idx) { }
+static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
 static void __init pud_advanced_tests(struct mm_struct *mm,
 				      struct vm_area_struct *vma, pud_t *pudp,
 				      unsigned long pfn, unsigned long vaddr,
@@ -413,8 +413,8 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 static void __init pud_leaf_tests(unsigned long pfn, pgprot_t prot) { }
 #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
 #else  /* !CONFIG_TRANSPARENT_HUGEPAGE */
-static void __init pmd_basic_tests(unsigned long pfn, int idx) { }
-static void __init pud_basic_tests(struct mm_struct *mm, unsigned long pfn, int idx) { }
+static void __init pmd_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
+static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
 static void __init pmd_advanced_tests(struct mm_struct *mm,
 				      struct vm_area_struct *vma, pmd_t *pmdp,
 				      unsigned long pfn, unsigned long vaddr,
@@ -475,7 +475,7 @@ static void __init pmd_huge_tests(pmd_t *pmdp, unsigned long pfn, pgprot_t prot)
 static void __init pud_huge_tests(pud_t *pudp, unsigned long pfn, pgprot_t prot) { }
 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
 
-static void __init p4d_basic_tests(unsigned long pfn, pgprot_t prot)
+static void __init p4d_basic_tests(void)
 {
 	p4d_t p4d;
 
@@ -484,7 +484,7 @@ static void __init p4d_basic_tests(unsigned long pfn, pgprot_t prot)
 	WARN_ON(!p4d_same(p4d, p4d));
 }
 
-static void __init pgd_basic_tests(unsigned long pfn, pgprot_t prot)
+static void __init pgd_basic_tests(void)
 {
 	pgd_t pgd;
 
@@ -889,7 +889,7 @@ static void __init swap_migration_tests(void)
 }
 
 #ifdef CONFIG_HUGETLB_PAGE
-static void __init hugetlb_basic_tests(unsigned long pfn, pgprot_t prot)
+static void __init hugetlb_basic_tests(struct vm_pgtable_debug *debug)
 {
 	struct page *page;
 	pte_t pte;
@@ -899,21 +899,21 @@ static void __init hugetlb_basic_tests(unsigned long pfn, pgprot_t prot)
 	 * Accessing the page associated with the pfn is safe here,
 	 * as it was previously derived from a real kernel symbol.
 	 */
-	page = pfn_to_page(pfn);
-	pte = mk_huge_pte(page, prot);
+	page = pfn_to_page(debug->fixed_pmd_pfn);
+	pte = mk_huge_pte(page, debug->page_prot);
 
 	WARN_ON(!huge_pte_dirty(huge_pte_mkdirty(pte)));
 	WARN_ON(!huge_pte_write(huge_pte_mkwrite(huge_pte_wrprotect(pte))));
 	WARN_ON(huge_pte_write(huge_pte_wrprotect(huge_pte_mkwrite(pte))));
 
 #ifdef CONFIG_ARCH_WANT_GENERAL_HUGETLB
-	pte = pfn_pte(pfn, prot);
+	pte = pfn_pte(debug->fixed_pmd_pfn, debug->page_prot);
 
 	WARN_ON(!pte_huge(pte_mkhuge(pte)));
 #endif /* CONFIG_ARCH_WANT_GENERAL_HUGETLB */
 }
 #else  /* !CONFIG_HUGETLB_PAGE */
-static void __init hugetlb_basic_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init hugetlb_basic_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -1248,9 +1248,9 @@ static int __init debug_vm_pgtable(void)
 	 * given page table entry.
 	 */
 	for (idx = 0; idx < ARRAY_SIZE(protection_map); idx++) {
-		pte_basic_tests(pte_aligned, idx);
-		pmd_basic_tests(pmd_aligned, idx);
-		pud_basic_tests(mm, pud_aligned, idx);
+		pte_basic_tests(&debug, idx);
+		pmd_basic_tests(&debug, idx);
+		pud_basic_tests(&debug, idx);
 	}
 
 	/*
@@ -1260,8 +1260,9 @@ static int __init debug_vm_pgtable(void)
 	 * the above iteration for now to save some test execution
 	 * time.
 	 */
-	p4d_basic_tests(p4d_aligned, prot);
-	pgd_basic_tests(pgd_aligned, prot);
+	p4d_basic_tests();
+	pgd_basic_tests();
+	hugetlb_basic_tests(&debug);
 
 	pmd_leaf_tests(pmd_aligned, prot);
 	pud_leaf_tests(pud_aligned, prot);
@@ -1290,8 +1291,6 @@ static int __init debug_vm_pgtable(void)
 	pmd_thp_tests(pmd_aligned, prot);
 	pud_thp_tests(pud_aligned, prot);
 
-	hugetlb_basic_tests(pte_aligned, prot);
-
 	/*
 	 * Page table modifying tests. They need to hold
 	 * proper page table lock.
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 03/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in leaf and savewrite tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
  2021-07-06  6:17 ` [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug Gavin Shan
  2021-07-06  6:17 ` [PATCH 02/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in basic tests Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 04/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in protnone and devmap tests Gavin Shan
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in the leaf and savewrite test
functions.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 759f27e1046e..00ddce30c6ca 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -160,9 +160,9 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
 	WARN_ON(pte_young(pte));
 }
 
-static void __init pte_savedwrite_tests(unsigned long pfn, pgprot_t prot)
+static void __init pte_savedwrite_tests(struct vm_pgtable_debug *debug)
 {
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte = pfn_pte(debug->fixed_pte_pfn, debug->page_prot_none);
 
 	if (!IS_ENABLED(CONFIG_NUMA_BALANCING))
 		return;
@@ -261,7 +261,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
 	pgtable = pgtable_trans_huge_withdraw(mm, pmdp);
 }
 
-static void __init pmd_leaf_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_leaf_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -269,7 +269,7 @@ static void __init pmd_leaf_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PMD leaf\n");
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot);
 
 	/*
 	 * PMD based THP is a leaf entry.
@@ -278,7 +278,7 @@ static void __init pmd_leaf_tests(unsigned long pfn, pgprot_t prot)
 	WARN_ON(!pmd_leaf(pmd));
 }
 
-static void __init pmd_savedwrite_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_savedwrite_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -289,7 +289,7 @@ static void __init pmd_savedwrite_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PMD saved write\n");
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot_none);
 	WARN_ON(!pmd_savedwrite(pmd_mk_savedwrite(pmd_clear_savedwrite(pmd))));
 	WARN_ON(pmd_savedwrite(pmd_clear_savedwrite(pmd_mk_savedwrite(pmd))));
 }
@@ -387,7 +387,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 	pudp_huge_get_and_clear(mm, vaddr, pudp);
 }
 
-static void __init pud_leaf_tests(unsigned long pfn, pgprot_t prot)
+static void __init pud_leaf_tests(struct vm_pgtable_debug *debug)
 {
 	pud_t pud;
 
@@ -395,7 +395,7 @@ static void __init pud_leaf_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PUD leaf\n");
-	pud = pfn_pud(pfn, prot);
+	pud = pfn_pud(debug->fixed_pud_pfn, debug->page_prot);
 	/*
 	 * PUD based THP is a leaf entry.
 	 */
@@ -410,7 +410,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 				      pgprot_t prot)
 {
 }
-static void __init pud_leaf_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pud_leaf_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
 #else  /* !CONFIG_TRANSPARENT_HUGEPAGE */
 static void __init pmd_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
@@ -427,9 +427,9 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 				      pgprot_t prot)
 {
 }
-static void __init pmd_leaf_tests(unsigned long pfn, pgprot_t prot) { }
-static void __init pud_leaf_tests(unsigned long pfn, pgprot_t prot) { }
-static void __init pmd_savedwrite_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pmd_leaf_tests(struct vm_pgtable_debug *debug) { }
+static void __init pud_leaf_tests(struct vm_pgtable_debug *debug) { }
+static void __init pmd_savedwrite_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
@@ -1264,11 +1264,11 @@ static int __init debug_vm_pgtable(void)
 	pgd_basic_tests();
 	hugetlb_basic_tests(&debug);
 
-	pmd_leaf_tests(pmd_aligned, prot);
-	pud_leaf_tests(pud_aligned, prot);
+	pmd_leaf_tests(&debug);
+	pud_leaf_tests(&debug);
 
-	pte_savedwrite_tests(pte_aligned, protnone);
-	pmd_savedwrite_tests(pmd_aligned, protnone);
+	pte_savedwrite_tests(&debug);
+	pmd_savedwrite_tests(&debug);
 
 	pte_special_tests(pte_aligned, prot);
 	pte_protnone_tests(pte_aligned, protnone);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 04/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in protnone and devmap tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (2 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 03/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in leaf and savewrite tests Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 05/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in soft_dirty and swap tests Gavin Shan
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in protnone and devmap test
functions.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 50 +++++++++++++++++++++----------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 00ddce30c6ca..cfb3dfb0447e 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -661,9 +661,9 @@ static void __init pmd_populate_tests(struct mm_struct *mm, pmd_t *pmdp,
 	WARN_ON(pmd_bad(pmd));
 }
 
-static void __init pte_special_tests(unsigned long pfn, pgprot_t prot)
+static void __init pte_special_tests(struct vm_pgtable_debug *debug)
 {
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte = pfn_pte(debug->fixed_pte_pfn, debug->page_prot);
 
 	if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_SPECIAL))
 		return;
@@ -672,9 +672,9 @@ static void __init pte_special_tests(unsigned long pfn, pgprot_t prot)
 	WARN_ON(!pte_special(pte_mkspecial(pte)));
 }
 
-static void __init pte_protnone_tests(unsigned long pfn, pgprot_t prot)
+static void __init pte_protnone_tests(struct vm_pgtable_debug *debug)
 {
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte = pfn_pte(debug->fixed_pte_pfn, debug->page_prot_none);
 
 	if (!IS_ENABLED(CONFIG_NUMA_BALANCING))
 		return;
@@ -685,7 +685,7 @@ static void __init pte_protnone_tests(unsigned long pfn, pgprot_t prot)
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static void __init pmd_protnone_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_protnone_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -696,25 +696,25 @@ static void __init pmd_protnone_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PMD protnone\n");
-	pmd = pmd_mkhuge(pfn_pmd(pfn, prot));
+	pmd = pmd_mkhuge(pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot_none));
 	WARN_ON(!pmd_protnone(pmd));
 	WARN_ON(!pmd_present(pmd));
 }
 #else  /* !CONFIG_TRANSPARENT_HUGEPAGE */
-static void __init pmd_protnone_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pmd_protnone_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #ifdef CONFIG_ARCH_HAS_PTE_DEVMAP
-static void __init pte_devmap_tests(unsigned long pfn, pgprot_t prot)
+static void __init pte_devmap_tests(struct vm_pgtable_debug *debug)
 {
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte = pfn_pte(debug->fixed_pte_pfn, debug->page_prot);
 
 	pr_debug("Validating PTE devmap\n");
 	WARN_ON(!pte_devmap(pte_mkdevmap(pte)));
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static void __init pmd_devmap_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_devmap_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -722,12 +722,12 @@ static void __init pmd_devmap_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PMD devmap\n");
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot);
 	WARN_ON(!pmd_devmap(pmd_mkdevmap(pmd)));
 }
 
 #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
-static void __init pud_devmap_tests(unsigned long pfn, pgprot_t prot)
+static void __init pud_devmap_tests(struct vm_pgtable_debug *debug)
 {
 	pud_t pud;
 
@@ -735,20 +735,20 @@ static void __init pud_devmap_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PUD devmap\n");
-	pud = pfn_pud(pfn, prot);
+	pud = pfn_pud(debug->fixed_pud_pfn, debug->page_prot);
 	WARN_ON(!pud_devmap(pud_mkdevmap(pud)));
 }
 #else  /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
-static void __init pud_devmap_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pud_devmap_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
 #else  /* CONFIG_TRANSPARENT_HUGEPAGE */
-static void __init pmd_devmap_tests(unsigned long pfn, pgprot_t prot) { }
-static void __init pud_devmap_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pmd_devmap_tests(struct vm_pgtable_debug *debug) { }
+static void __init pud_devmap_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 #else
-static void __init pte_devmap_tests(unsigned long pfn, pgprot_t prot) { }
-static void __init pmd_devmap_tests(unsigned long pfn, pgprot_t prot) { }
-static void __init pud_devmap_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pte_devmap_tests(struct vm_pgtable_debug *debug) { }
+static void __init pmd_devmap_tests(struct vm_pgtable_debug *debug) { }
+static void __init pud_devmap_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_ARCH_HAS_PTE_DEVMAP */
 
 static void __init pte_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
@@ -1270,13 +1270,13 @@ static int __init debug_vm_pgtable(void)
 	pte_savedwrite_tests(&debug);
 	pmd_savedwrite_tests(&debug);
 
-	pte_special_tests(pte_aligned, prot);
-	pte_protnone_tests(pte_aligned, protnone);
-	pmd_protnone_tests(pmd_aligned, protnone);
+	pte_special_tests(&debug);
+	pte_protnone_tests(&debug);
+	pmd_protnone_tests(&debug);
 
-	pte_devmap_tests(pte_aligned, prot);
-	pmd_devmap_tests(pmd_aligned, prot);
-	pud_devmap_tests(pud_aligned, prot);
+	pte_devmap_tests(&debug);
+	pmd_devmap_tests(&debug);
+	pud_devmap_tests(&debug);
 
 	pte_soft_dirty_tests(pte_aligned, prot);
 	pmd_soft_dirty_tests(pmd_aligned, prot);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 05/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in soft_dirty and swap tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (3 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 04/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in protnone and devmap tests Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 06/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in migration and thp tests Gavin Shan
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in the soft_dirty and swap test
functions.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 48 +++++++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 25 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index cfb3dfb0447e..eb0a836a73ad 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -751,9 +751,9 @@ static void __init pmd_devmap_tests(struct vm_pgtable_debug *debug) { }
 static void __init pud_devmap_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_ARCH_HAS_PTE_DEVMAP */
 
-static void __init pte_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
+static void __init pte_soft_dirty_tests(struct vm_pgtable_debug *debug)
 {
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte = pfn_pte(debug->fixed_pte_pfn, debug->page_prot);
 
 	if (!IS_ENABLED(CONFIG_MEM_SOFT_DIRTY))
 		return;
@@ -763,9 +763,9 @@ static void __init pte_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
 	WARN_ON(pte_soft_dirty(pte_clear_soft_dirty(pte)));
 }
 
-static void __init pte_swap_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
+static void __init pte_swap_soft_dirty_tests(struct vm_pgtable_debug *debug)
 {
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte = pfn_pte(debug->fixed_pte_pfn, debug->page_prot);
 
 	if (!IS_ENABLED(CONFIG_MEM_SOFT_DIRTY))
 		return;
@@ -776,7 +776,7 @@ static void __init pte_swap_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static void __init pmd_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_soft_dirty_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -787,12 +787,12 @@ static void __init pmd_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PMD soft dirty\n");
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot);
 	WARN_ON(!pmd_soft_dirty(pmd_mksoft_dirty(pmd)));
 	WARN_ON(pmd_soft_dirty(pmd_clear_soft_dirty(pmd)));
 }
 
-static void __init pmd_swap_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_swap_soft_dirty_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -804,31 +804,29 @@ static void __init pmd_swap_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PMD swap soft dirty\n");
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot);
 	WARN_ON(!pmd_swp_soft_dirty(pmd_swp_mksoft_dirty(pmd)));
 	WARN_ON(pmd_swp_soft_dirty(pmd_swp_clear_soft_dirty(pmd)));
 }
 #else  /* !CONFIG_TRANSPARENT_HUGEPAGE */
-static void __init pmd_soft_dirty_tests(unsigned long pfn, pgprot_t prot) { }
-static void __init pmd_swap_soft_dirty_tests(unsigned long pfn, pgprot_t prot)
-{
-}
+static void __init pmd_soft_dirty_tests(struct vm_pgtable_debug *debug) { }
+static void __init pmd_swap_soft_dirty_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-static void __init pte_swap_tests(unsigned long pfn, pgprot_t prot)
+static void __init pte_swap_tests(struct vm_pgtable_debug *debug)
 {
 	swp_entry_t swp;
 	pte_t pte;
 
 	pr_debug("Validating PTE swap\n");
-	pte = pfn_pte(pfn, prot);
+	pte = pfn_pte(debug->fixed_pte_pfn, debug->page_prot);
 	swp = __pte_to_swp_entry(pte);
 	pte = __swp_entry_to_pte(swp);
-	WARN_ON(pfn != pte_pfn(pte));
+	WARN_ON(debug->fixed_pte_pfn != pte_pfn(pte));
 }
 
 #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
-static void __init pmd_swap_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_swap_tests(struct vm_pgtable_debug *debug)
 {
 	swp_entry_t swp;
 	pmd_t pmd;
@@ -837,13 +835,13 @@ static void __init pmd_swap_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PMD swap\n");
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot);
 	swp = __pmd_to_swp_entry(pmd);
 	pmd = __swp_entry_to_pmd(swp);
-	WARN_ON(pfn != pmd_pfn(pmd));
+	WARN_ON(debug->fixed_pmd_pfn != pmd_pfn(pmd));
 }
 #else  /* !CONFIG_ARCH_ENABLE_THP_MIGRATION */
-static void __init pmd_swap_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pmd_swap_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
 
 static void __init swap_migration_tests(void)
@@ -1278,13 +1276,13 @@ static int __init debug_vm_pgtable(void)
 	pmd_devmap_tests(&debug);
 	pud_devmap_tests(&debug);
 
-	pte_soft_dirty_tests(pte_aligned, prot);
-	pmd_soft_dirty_tests(pmd_aligned, prot);
-	pte_swap_soft_dirty_tests(pte_aligned, prot);
-	pmd_swap_soft_dirty_tests(pmd_aligned, prot);
+	pte_soft_dirty_tests(&debug);
+	pmd_soft_dirty_tests(&debug);
+	pte_swap_soft_dirty_tests(&debug);
+	pmd_swap_soft_dirty_tests(&debug);
 
-	pte_swap_tests(pte_aligned, prot);
-	pmd_swap_tests(pmd_aligned, prot);
+	pte_swap_tests(&debug);
+	pmd_swap_tests(&debug);
 
 	swap_migration_tests();
 
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 06/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in migration and thp tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (4 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 05/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in soft_dirty and swap tests Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 07/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PTE modifying tests Gavin Shan
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in the migration and thp test
functions. It's notable that the pre-allocated page is used in
swap_migration_tests() as set_pte_at() is used there.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index eb0a836a73ad..757d2d9c4e93 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -844,7 +844,7 @@ static void __init pmd_swap_tests(struct vm_pgtable_debug *debug)
 static void __init pmd_swap_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
 
-static void __init swap_migration_tests(void)
+static void __init swap_migration_tests(struct vm_pgtable_debug *debug)
 {
 	struct page *page;
 	swp_entry_t swp;
@@ -860,9 +860,10 @@ static void __init swap_migration_tests(void)
 	 * problematic. Lets allocate a dedicated page explicitly for this
 	 * purpose that will be freed subsequently.
 	 */
-	page = alloc_page(GFP_KERNEL);
+	page = (debug->pte_pfn != ULONG_MAX) ?
+	       pfn_to_page(debug->pte_pfn) : NULL;
 	if (!page) {
-		pr_err("page allocation failed\n");
+		pr_err("no page available\n");
 		return;
 	}
 
@@ -883,7 +884,6 @@ static void __init swap_migration_tests(void)
 	WARN_ON(!is_migration_entry(swp));
 	WARN_ON(is_writable_migration_entry(swp));
 	__ClearPageLocked(page);
-	__free_page(page);
 }
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -915,7 +915,7 @@ static void __init hugetlb_basic_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static void __init pmd_thp_tests(unsigned long pfn, pgprot_t prot)
+static void __init pmd_thp_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -934,7 +934,7 @@ static void __init pmd_thp_tests(unsigned long pfn, pgprot_t prot)
 	 * needs to return true. pmd_present() should be true whenever
 	 * pmd_trans_huge() returns true.
 	 */
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->fixed_pmd_pfn, debug->page_prot);
 	WARN_ON(!pmd_trans_huge(pmd_mkhuge(pmd)));
 
 #ifndef __HAVE_ARCH_PMDP_INVALIDATE
@@ -944,7 +944,7 @@ static void __init pmd_thp_tests(unsigned long pfn, pgprot_t prot)
 }
 
 #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
-static void __init pud_thp_tests(unsigned long pfn, pgprot_t prot)
+static void __init pud_thp_tests(struct vm_pgtable_debug *debug)
 {
 	pud_t pud;
 
@@ -952,7 +952,7 @@ static void __init pud_thp_tests(unsigned long pfn, pgprot_t prot)
 		return;
 
 	pr_debug("Validating PUD based THP\n");
-	pud = pfn_pud(pfn, prot);
+	pud = pfn_pud(debug->fixed_pud_pfn, debug->page_prot);
 	WARN_ON(!pud_trans_huge(pud_mkhuge(pud)));
 
 	/*
@@ -964,11 +964,11 @@ static void __init pud_thp_tests(unsigned long pfn, pgprot_t prot)
 	 */
 }
 #else  /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
-static void __init pud_thp_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pud_thp_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
 #else  /* !CONFIG_TRANSPARENT_HUGEPAGE */
-static void __init pmd_thp_tests(unsigned long pfn, pgprot_t prot) { }
-static void __init pud_thp_tests(unsigned long pfn, pgprot_t prot) { }
+static void __init pmd_thp_tests(struct vm_pgtable_debug *debug) { }
+static void __init pud_thp_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 static unsigned long __init get_random_vaddr(void)
@@ -1284,10 +1284,10 @@ static int __init debug_vm_pgtable(void)
 	pte_swap_tests(&debug);
 	pmd_swap_tests(&debug);
 
-	swap_migration_tests();
+	swap_migration_tests(&debug);
 
-	pmd_thp_tests(pmd_aligned, prot);
-	pud_thp_tests(pud_aligned, prot);
+	pmd_thp_tests(&debug);
+	pud_thp_tests(&debug);
 
 	/*
 	 * Page table modifying tests. They need to hold
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 07/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PTE modifying tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (5 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 06/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in migration and thp tests Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 08/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PMD " Gavin Shan
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in PTE modifying tests. The allocated
page is used as set_pte_at() is used there. The tests are skipped if
the allocated page doesn't exist.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 71 +++++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 33 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 757d2d9c4e93..2b4f0738f266 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -116,10 +116,7 @@ static void __init pte_basic_tests(struct vm_pgtable_debug *debug, int idx)
 	WARN_ON(!pte_dirty(pte_wrprotect(pte_mkdirty(pte))));
 }
 
-static void __init pte_advanced_tests(struct mm_struct *mm,
-				      struct vm_area_struct *vma, pte_t *ptep,
-				      unsigned long pfn, unsigned long vaddr,
-				      pgprot_t prot)
+static void __init pte_advanced_tests(struct vm_pgtable_debug *debug)
 {
 	pte_t pte;
 
@@ -130,33 +127,38 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
 	 */
 
 	pr_debug("Validating PTE advanced\n");
-	pte = pfn_pte(pfn, prot);
-	set_pte_at(mm, vaddr, ptep, pte);
-	ptep_set_wrprotect(mm, vaddr, ptep);
-	pte = ptep_get(ptep);
+	if (debug->pte_pfn == ULONG_MAX) {
+		pr_debug("%s: Skipped\n", __func__);
+		return;
+	}
+
+	pte = pfn_pte(debug->pte_pfn, debug->page_prot);
+	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
+	ptep_set_wrprotect(debug->mm, debug->vaddr, debug->ptep);
+	pte = ptep_get(debug->ptep);
 	WARN_ON(pte_write(pte));
-	ptep_get_and_clear(mm, vaddr, ptep);
-	pte = ptep_get(ptep);
+	ptep_get_and_clear(debug->mm, debug->vaddr, debug->ptep);
+	pte = ptep_get(debug->ptep);
 	WARN_ON(!pte_none(pte));
 
-	pte = pfn_pte(pfn, prot);
+	pte = pfn_pte(debug->pte_pfn, debug->page_prot);
 	pte = pte_wrprotect(pte);
 	pte = pte_mkclean(pte);
-	set_pte_at(mm, vaddr, ptep, pte);
+	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
 	pte = pte_mkwrite(pte);
 	pte = pte_mkdirty(pte);
-	ptep_set_access_flags(vma, vaddr, ptep, pte, 1);
-	pte = ptep_get(ptep);
+	ptep_set_access_flags(debug->vma, debug->vaddr, debug->ptep, pte, 1);
+	pte = ptep_get(debug->ptep);
 	WARN_ON(!(pte_write(pte) && pte_dirty(pte)));
-	ptep_get_and_clear_full(mm, vaddr, ptep, 1);
-	pte = ptep_get(ptep);
+	ptep_get_and_clear_full(debug->mm, debug->vaddr, debug->ptep, 1);
+	pte = ptep_get(debug->ptep);
 	WARN_ON(!pte_none(pte));
 
-	pte = pfn_pte(pfn, prot);
+	pte = pfn_pte(debug->pte_pfn, debug->page_prot);
 	pte = pte_mkyoung(pte);
-	set_pte_at(mm, vaddr, ptep, pte);
-	ptep_test_and_clear_young(vma, vaddr, ptep);
-	pte = ptep_get(ptep);
+	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
+	ptep_test_and_clear_young(debug->vma, debug->vaddr, debug->ptep);
+	pte = ptep_get(debug->ptep);
 	WARN_ON(pte_young(pte));
 }
 
@@ -617,20 +619,24 @@ static void __init pgd_populate_tests(struct mm_struct *mm, pgd_t *pgdp,
 }
 #endif /* PAGETABLE_P4D_FOLDED */
 
-static void __init pte_clear_tests(struct mm_struct *mm, pte_t *ptep,
-				   unsigned long pfn, unsigned long vaddr,
-				   pgprot_t prot)
+static void __init pte_clear_tests(struct vm_pgtable_debug *debug)
 {
-	pte_t pte = pfn_pte(pfn, prot);
+	pte_t pte;
 
 	pr_debug("Validating PTE clear\n");
+	if (debug->pte_pfn == ULONG_MAX) {
+		pr_debug("%s: Skipped\n", __func__);
+		return;
+	}
+
+	pte = pfn_pte(debug->pte_pfn, debug->page_prot);
 #ifndef CONFIG_RISCV
 	pte = __pte(pte_val(pte) | RANDOM_ORVALUE);
 #endif
-	set_pte_at(mm, vaddr, ptep, pte);
+	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
 	barrier();
-	pte_clear(mm, vaddr, ptep);
-	pte = ptep_get(ptep);
+	pte_clear(debug->mm, debug->vaddr, debug->ptep);
+	pte = ptep_get(debug->ptep);
 	WARN_ON(!pte_none(pte));
 }
 
@@ -1163,7 +1169,6 @@ static int __init debug_vm_pgtable(void)
 	p4d_t *p4dp, *saved_p4dp;
 	pud_t *pudp, *saved_pudp;
 	pmd_t *pmdp, *saved_pmdp, pmd;
-	pte_t *ptep;
 	pgtable_t saved_ptep;
 	pgprot_t prot, protnone;
 	phys_addr_t paddr;
@@ -1293,11 +1298,11 @@ static int __init debug_vm_pgtable(void)
 	 * Page table modifying tests. They need to hold
 	 * proper page table lock.
 	 */
-
-	ptep = pte_offset_map_lock(mm, pmdp, vaddr, &ptl);
-	pte_clear_tests(mm, ptep, pte_aligned, vaddr, prot);
-	pte_advanced_tests(mm, vma, ptep, pte_aligned, vaddr, prot);
-	pte_unmap_unlock(ptep, ptl);
+	ptl = pte_lockptr(debug.mm, debug.pmdp);
+	spin_lock(ptl);
+	pte_clear_tests(&debug);
+	pte_advanced_tests(&debug);
+	spin_unlock(ptl);
 
 	ptl = pmd_lock(mm, pmdp);
 	pmd_clear_tests(mm, pmdp);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 08/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PMD modifying tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (6 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 07/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PTE modifying tests Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 09/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in PUD " Gavin Shan
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in PMD modifying tests. The allocated
huge page is used when set_pmd_at() is used. The corresponding tests
are skipped if the huge page doesn't exist.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 99 ++++++++++++++++++++-----------------------
 1 file changed, 47 insertions(+), 52 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 2b4f0738f266..c554b6c42281 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -213,54 +213,54 @@ static void __init pmd_basic_tests(struct vm_pgtable_debug *debug, int idx)
 	WARN_ON(!pmd_bad(pmd_mkhuge(pmd)));
 }
 
-static void __init pmd_advanced_tests(struct mm_struct *mm,
-				      struct vm_area_struct *vma, pmd_t *pmdp,
-				      unsigned long pfn, unsigned long vaddr,
-				      pgprot_t prot, pgtable_t pgtable)
+static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
+	unsigned long vaddr = (debug->vaddr & HPAGE_PMD_MASK);
 
 	if (!has_transparent_hugepage())
 		return;
 
 	pr_debug("Validating PMD advanced\n");
-	/* Align the address wrt HPAGE_PMD_SIZE */
-	vaddr &= HPAGE_PMD_MASK;
+	if (debug->pmd_pfn == ULONG_MAX) {
+		pr_debug("%s: Skipped\n", __func__);
+		return;
+	}
 
-	pgtable_trans_huge_deposit(mm, pmdp, pgtable);
+	pgtable_trans_huge_deposit(debug->mm, debug->pmdp, debug->start_ptep);
 
-	pmd = pfn_pmd(pfn, prot);
-	set_pmd_at(mm, vaddr, pmdp, pmd);
-	pmdp_set_wrprotect(mm, vaddr, pmdp);
-	pmd = READ_ONCE(*pmdp);
+	pmd = pfn_pmd(debug->pmd_pfn, debug->page_prot);
+	set_pmd_at(debug->mm, vaddr, debug->pmdp, pmd);
+	pmdp_set_wrprotect(debug->mm, vaddr, debug->pmdp);
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(pmd_write(pmd));
-	pmdp_huge_get_and_clear(mm, vaddr, pmdp);
-	pmd = READ_ONCE(*pmdp);
+	pmdp_huge_get_and_clear(debug->mm, vaddr, debug->pmdp);
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(!pmd_none(pmd));
 
-	pmd = pfn_pmd(pfn, prot);
+	pmd = pfn_pmd(debug->pmd_pfn, debug->page_prot);
 	pmd = pmd_wrprotect(pmd);
 	pmd = pmd_mkclean(pmd);
-	set_pmd_at(mm, vaddr, pmdp, pmd);
+	set_pmd_at(debug->mm, vaddr, debug->pmdp, pmd);
 	pmd = pmd_mkwrite(pmd);
 	pmd = pmd_mkdirty(pmd);
-	pmdp_set_access_flags(vma, vaddr, pmdp, pmd, 1);
-	pmd = READ_ONCE(*pmdp);
+	pmdp_set_access_flags(debug->vma, vaddr, debug->pmdp, pmd, 1);
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(!(pmd_write(pmd) && pmd_dirty(pmd)));
-	pmdp_huge_get_and_clear_full(vma, vaddr, pmdp, 1);
-	pmd = READ_ONCE(*pmdp);
+	pmdp_huge_get_and_clear_full(debug->vma, vaddr, debug->pmdp, 1);
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(!pmd_none(pmd));
 
-	pmd = pmd_mkhuge(pfn_pmd(pfn, prot));
+	pmd = pmd_mkhuge(pfn_pmd(debug->pmd_pfn, debug->page_prot));
 	pmd = pmd_mkyoung(pmd);
-	set_pmd_at(mm, vaddr, pmdp, pmd);
-	pmdp_test_and_clear_young(vma, vaddr, pmdp);
-	pmd = READ_ONCE(*pmdp);
+	set_pmd_at(debug->mm, vaddr, debug->pmdp, pmd);
+	pmdp_test_and_clear_young(debug->vma, vaddr, debug->pmdp);
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(pmd_young(pmd));
 
 	/*  Clear the pte entries  */
-	pmdp_huge_get_and_clear(mm, vaddr, pmdp);
-	pgtable = pgtable_trans_huge_withdraw(mm, pmdp);
+	pmdp_huge_get_and_clear(debug->mm, vaddr, debug->pmdp);
+	pgtable_trans_huge_withdraw(debug->mm, debug->pmdp);
 }
 
 static void __init pmd_leaf_tests(struct vm_pgtable_debug *debug)
@@ -417,12 +417,7 @@ static void __init pud_leaf_tests(struct vm_pgtable_debug *debug) { }
 #else  /* !CONFIG_TRANSPARENT_HUGEPAGE */
 static void __init pmd_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
 static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
-static void __init pmd_advanced_tests(struct mm_struct *mm,
-				      struct vm_area_struct *vma, pmd_t *pmdp,
-				      unsigned long pfn, unsigned long vaddr,
-				      pgprot_t prot, pgtable_t pgtable)
-{
-}
+static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug) { }
 static void __init pud_advanced_tests(struct mm_struct *mm,
 				      struct vm_area_struct *vma, pud_t *pudp,
 				      unsigned long pfn, unsigned long vaddr,
@@ -435,11 +430,11 @@ static void __init pmd_savedwrite_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
-static void __init pmd_huge_tests(pmd_t *pmdp, unsigned long pfn, pgprot_t prot)
+static void __init pmd_huge_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
-	if (!arch_vmap_pmd_supported(prot))
+	if (!arch_vmap_pmd_supported(debug->page_prot))
 		return;
 
 	pr_debug("Validating PMD huge\n");
@@ -447,10 +442,11 @@ static void __init pmd_huge_tests(pmd_t *pmdp, unsigned long pfn, pgprot_t prot)
 	 * X86 defined pmd_set_huge() verifies that the given
 	 * PMD is not a populated non-leaf entry.
 	 */
-	WRITE_ONCE(*pmdp, __pmd(0));
-	WARN_ON(!pmd_set_huge(pmdp, __pfn_to_phys(pfn), prot));
-	WARN_ON(!pmd_clear_huge(pmdp));
-	pmd = READ_ONCE(*pmdp);
+	WRITE_ONCE(*(debug->pmdp), __pmd(0));
+	WARN_ON(!pmd_set_huge(debug->pmdp, __pfn_to_phys(debug->fixed_pmd_pfn),
+			      debug->page_prot));
+	WARN_ON(!pmd_clear_huge(debug->pmdp));
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(!pmd_none(pmd));
 }
 
@@ -473,7 +469,7 @@ static void __init pud_huge_tests(pud_t *pudp, unsigned long pfn, pgprot_t prot)
 	WARN_ON(!pud_none(pud));
 }
 #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
-static void __init pmd_huge_tests(pmd_t *pmdp, unsigned long pfn, pgprot_t prot) { }
+static void __init pmd_huge_tests(struct vm_pgtable_debug *debug) { }
 static void __init pud_huge_tests(pud_t *pudp, unsigned long pfn, pgprot_t prot) { }
 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
 
@@ -640,20 +636,19 @@ static void __init pte_clear_tests(struct vm_pgtable_debug *debug)
 	WARN_ON(!pte_none(pte));
 }
 
-static void __init pmd_clear_tests(struct mm_struct *mm, pmd_t *pmdp)
+static void __init pmd_clear_tests(struct vm_pgtable_debug *debug)
 {
-	pmd_t pmd = READ_ONCE(*pmdp);
+	pmd_t pmd = READ_ONCE(*(debug->pmdp));
 
 	pr_debug("Validating PMD clear\n");
 	pmd = __pmd(pmd_val(pmd) | RANDOM_ORVALUE);
-	WRITE_ONCE(*pmdp, pmd);
-	pmd_clear(pmdp);
-	pmd = READ_ONCE(*pmdp);
+	WRITE_ONCE(*(debug->pmdp), pmd);
+	pmd_clear(debug->pmdp);
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(!pmd_none(pmd));
 }
 
-static void __init pmd_populate_tests(struct mm_struct *mm, pmd_t *pmdp,
-				      pgtable_t pgtable)
+static void __init pmd_populate_tests(struct vm_pgtable_debug *debug)
 {
 	pmd_t pmd;
 
@@ -662,8 +657,8 @@ static void __init pmd_populate_tests(struct mm_struct *mm, pmd_t *pmdp,
 	 * This entry points to next level page table page.
 	 * Hence this must not qualify as pmd_bad().
 	 */
-	pmd_populate(mm, pmdp, pgtable);
-	pmd = READ_ONCE(*pmdp);
+	pmd_populate(debug->mm, debug->pmdp, debug->start_ptep);
+	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(pmd_bad(pmd));
 }
 
@@ -1304,11 +1299,11 @@ static int __init debug_vm_pgtable(void)
 	pte_advanced_tests(&debug);
 	spin_unlock(ptl);
 
-	ptl = pmd_lock(mm, pmdp);
-	pmd_clear_tests(mm, pmdp);
-	pmd_advanced_tests(mm, vma, pmdp, pmd_aligned, vaddr, prot, saved_ptep);
-	pmd_huge_tests(pmdp, pmd_aligned, prot);
-	pmd_populate_tests(mm, pmdp, saved_ptep);
+	ptl = pmd_lock(debug.mm, debug.pmdp);
+	pmd_clear_tests(&debug);
+	pmd_advanced_tests(&debug);
+	pmd_huge_tests(&debug);
+	pmd_populate_tests(&debug);
 	spin_unlock(ptl);
 
 	ptl = pud_lock(mm, pudp);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 09/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in PUD modifying tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (7 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 08/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PMD " Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 10/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PGD and P4D " Gavin Shan
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in PUD modifying tests. The allocated
huge page is used when set_pud_at() is used. The corresponding tests
are skipped if the huge page doesn't exist.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 113 +++++++++++++++++++-----------------------
 1 file changed, 50 insertions(+), 63 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index c554b6c42281..59fd9440ab12 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -338,55 +338,55 @@ static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx)
 	WARN_ON(!pud_bad(pud_mkhuge(pud)));
 }
 
-static void __init pud_advanced_tests(struct mm_struct *mm,
-				      struct vm_area_struct *vma, pud_t *pudp,
-				      unsigned long pfn, unsigned long vaddr,
-				      pgprot_t prot)
+static void __init pud_advanced_tests(struct vm_pgtable_debug *debug)
 {
+	unsigned long vaddr = (debug->vaddr & HPAGE_PUD_MASK);
 	pud_t pud;
 
 	if (!has_transparent_hugepage())
 		return;
 
 	pr_debug("Validating PUD advanced\n");
-	/* Align the address wrt HPAGE_PUD_SIZE */
-	vaddr &= HPAGE_PUD_MASK;
+	if (debug->pud_pfn == ULONG_MAX) {
+		pr_debug("%s: Skipped\n", __func__);
+		return;
+	}
 
-	pud = pfn_pud(pfn, prot);
-	set_pud_at(mm, vaddr, pudp, pud);
-	pudp_set_wrprotect(mm, vaddr, pudp);
-	pud = READ_ONCE(*pudp);
+	pud = pfn_pud(debug->pud_pfn, debug->page_prot);
+	set_pud_at(debug->mm, vaddr, debug->pudp, pud);
+	pudp_set_wrprotect(debug->mm, vaddr, debug->pudp);
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(pud_write(pud));
 
 #ifndef __PAGETABLE_PMD_FOLDED
-	pudp_huge_get_and_clear(mm, vaddr, pudp);
-	pud = READ_ONCE(*pudp);
+	pudp_huge_get_and_clear(debug->mm, vaddr, debug->pudp);
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(!pud_none(pud));
 #endif /* __PAGETABLE_PMD_FOLDED */
-	pud = pfn_pud(pfn, prot);
+	pud = pfn_pud(debug->pud_pfn, debug->page_prot);
 	pud = pud_wrprotect(pud);
 	pud = pud_mkclean(pud);
-	set_pud_at(mm, vaddr, pudp, pud);
+	set_pud_at(debug->mm, vaddr, debug->pudp, pud);
 	pud = pud_mkwrite(pud);
 	pud = pud_mkdirty(pud);
-	pudp_set_access_flags(vma, vaddr, pudp, pud, 1);
-	pud = READ_ONCE(*pudp);
+	pudp_set_access_flags(debug->vma, vaddr, debug->pudp, pud, 1);
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(!(pud_write(pud) && pud_dirty(pud)));
 
 #ifndef __PAGETABLE_PMD_FOLDED
-	pudp_huge_get_and_clear_full(mm, vaddr, pudp, 1);
-	pud = READ_ONCE(*pudp);
+	pudp_huge_get_and_clear_full(debug->mm, vaddr, debug->pudp, 1);
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(!pud_none(pud));
 #endif /* __PAGETABLE_PMD_FOLDED */
 
-	pud = pfn_pud(pfn, prot);
+	pud = pfn_pud(debug->pud_pfn, debug->page_prot);
 	pud = pud_mkyoung(pud);
-	set_pud_at(mm, vaddr, pudp, pud);
-	pudp_test_and_clear_young(vma, vaddr, pudp);
-	pud = READ_ONCE(*pudp);
+	set_pud_at(debug->mm, vaddr, debug->pudp, pud);
+	pudp_test_and_clear_young(debug->vma, vaddr, debug->pudp);
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(pud_young(pud));
 
-	pudp_huge_get_and_clear(mm, vaddr, pudp);
+	pudp_huge_get_and_clear(debug->mm, vaddr, debug->pudp);
 }
 
 static void __init pud_leaf_tests(struct vm_pgtable_debug *debug)
@@ -406,24 +406,14 @@ static void __init pud_leaf_tests(struct vm_pgtable_debug *debug)
 }
 #else  /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
 static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
-static void __init pud_advanced_tests(struct mm_struct *mm,
-				      struct vm_area_struct *vma, pud_t *pudp,
-				      unsigned long pfn, unsigned long vaddr,
-				      pgprot_t prot)
-{
-}
+static void __init pud_advanced_tests(struct vm_pgtable_debug *debug) { }
 static void __init pud_leaf_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
 #else  /* !CONFIG_TRANSPARENT_HUGEPAGE */
 static void __init pmd_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
 static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx) { }
 static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug) { }
-static void __init pud_advanced_tests(struct mm_struct *mm,
-				      struct vm_area_struct *vma, pud_t *pudp,
-				      unsigned long pfn, unsigned long vaddr,
-				      pgprot_t prot)
-{
-}
+static void __init pud_advanced_tests(struct vm_pgtable_debug *debug) { }
 static void __init pmd_leaf_tests(struct vm_pgtable_debug *debug) { }
 static void __init pud_leaf_tests(struct vm_pgtable_debug *debug) { }
 static void __init pmd_savedwrite_tests(struct vm_pgtable_debug *debug) { }
@@ -450,11 +440,11 @@ static void __init pmd_huge_tests(struct vm_pgtable_debug *debug)
 	WARN_ON(!pmd_none(pmd));
 }
 
-static void __init pud_huge_tests(pud_t *pudp, unsigned long pfn, pgprot_t prot)
+static void __init pud_huge_tests(struct vm_pgtable_debug *debug)
 {
 	pud_t pud;
 
-	if (!arch_vmap_pud_supported(prot))
+	if (!arch_vmap_pud_supported(debug->page_prot))
 		return;
 
 	pr_debug("Validating PUD huge\n");
@@ -462,15 +452,16 @@ static void __init pud_huge_tests(pud_t *pudp, unsigned long pfn, pgprot_t prot)
 	 * X86 defined pud_set_huge() verifies that the given
 	 * PUD is not a populated non-leaf entry.
 	 */
-	WRITE_ONCE(*pudp, __pud(0));
-	WARN_ON(!pud_set_huge(pudp, __pfn_to_phys(pfn), prot));
-	WARN_ON(!pud_clear_huge(pudp));
-	pud = READ_ONCE(*pudp);
+	WRITE_ONCE(*(debug->pudp), __pud(0));
+	WARN_ON(!pud_set_huge(debug->pudp, __pfn_to_phys(debug->fixed_pud_pfn),
+			      debug->page_prot));
+	WARN_ON(!pud_clear_huge(debug->pudp));
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(!pud_none(pud));
 }
 #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
 static void __init pmd_huge_tests(struct vm_pgtable_debug *debug) { }
-static void __init pud_huge_tests(pud_t *pudp, unsigned long pfn, pgprot_t prot) { }
+static void __init pud_huge_tests(struct vm_pgtable_debug *debug) { }
 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
 
 static void __init p4d_basic_tests(void)
@@ -492,27 +483,26 @@ static void __init pgd_basic_tests(void)
 }
 
 #ifndef __PAGETABLE_PUD_FOLDED
-static void __init pud_clear_tests(struct mm_struct *mm, pud_t *pudp)
+static void __init pud_clear_tests(struct vm_pgtable_debug *debug)
 {
-	pud_t pud = READ_ONCE(*pudp);
+	pud_t pud = READ_ONCE(*(debug->pudp));
 
-	if (mm_pmd_folded(mm))
+	if (mm_pmd_folded(debug->mm))
 		return;
 
 	pr_debug("Validating PUD clear\n");
 	pud = __pud(pud_val(pud) | RANDOM_ORVALUE);
-	WRITE_ONCE(*pudp, pud);
-	pud_clear(pudp);
-	pud = READ_ONCE(*pudp);
+	WRITE_ONCE(*(debug->pudp), pud);
+	pud_clear(debug->pudp);
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(!pud_none(pud));
 }
 
-static void __init pud_populate_tests(struct mm_struct *mm, pud_t *pudp,
-				      pmd_t *pmdp)
+static void __init pud_populate_tests(struct vm_pgtable_debug *debug)
 {
 	pud_t pud;
 
-	if (mm_pmd_folded(mm))
+	if (mm_pmd_folded(debug->mm))
 		return;
 
 	pr_debug("Validating PUD populate\n");
@@ -520,16 +510,13 @@ static void __init pud_populate_tests(struct mm_struct *mm, pud_t *pudp,
 	 * This entry points to next level page table page.
 	 * Hence this must not qualify as pud_bad().
 	 */
-	pud_populate(mm, pudp, pmdp);
-	pud = READ_ONCE(*pudp);
+	pud_populate(debug->mm, debug->pudp, debug->start_pmdp);
+	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(pud_bad(pud));
 }
 #else  /* !__PAGETABLE_PUD_FOLDED */
-static void __init pud_clear_tests(struct mm_struct *mm, pud_t *pudp) { }
-static void __init pud_populate_tests(struct mm_struct *mm, pud_t *pudp,
-				      pmd_t *pmdp)
-{
-}
+static void __init pud_clear_tests(struct vm_pgtable_debug *debug) { }
+static void __init pud_populate_tests(struct vm_pgtable_debug *debug) { }
 #endif /* PAGETABLE_PUD_FOLDED */
 
 #ifndef __PAGETABLE_P4D_FOLDED
@@ -1306,11 +1293,11 @@ static int __init debug_vm_pgtable(void)
 	pmd_populate_tests(&debug);
 	spin_unlock(ptl);
 
-	ptl = pud_lock(mm, pudp);
-	pud_clear_tests(mm, pudp);
-	pud_advanced_tests(mm, vma, pudp, pud_aligned, vaddr, prot);
-	pud_huge_tests(pudp, pud_aligned, prot);
-	pud_populate_tests(mm, pudp, saved_pmdp);
+	ptl = pud_lock(debug.mm, debug.pudp);
+	pud_clear_tests(&debug);
+	pud_advanced_tests(&debug);
+	pud_huge_tests(&debug);
+	pud_populate_tests(&debug);
 	spin_unlock(ptl);
 
 	spin_lock(&mm->page_table_lock);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 10/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PGD and P4D modifying tests
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (8 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 09/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in PUD " Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 11/12] mm/debug_vm_pgtable: Remove unused code Gavin Shan
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

This uses struct vm_pgtable_debug in PGD/P4D modifying tests. No
allocated huge page is used in these tests.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 76 +++++++++++++++++++------------------------
 1 file changed, 34 insertions(+), 42 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 59fd9440ab12..7bc26808033c 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -520,27 +520,26 @@ static void __init pud_populate_tests(struct vm_pgtable_debug *debug) { }
 #endif /* PAGETABLE_PUD_FOLDED */
 
 #ifndef __PAGETABLE_P4D_FOLDED
-static void __init p4d_clear_tests(struct mm_struct *mm, p4d_t *p4dp)
+static void __init p4d_clear_tests(struct vm_pgtable_debug *debug)
 {
-	p4d_t p4d = READ_ONCE(*p4dp);
+	p4d_t p4d = READ_ONCE(*(debug->p4dp));
 
-	if (mm_pud_folded(mm))
+	if (mm_pud_folded(debug->mm))
 		return;
 
 	pr_debug("Validating P4D clear\n");
 	p4d = __p4d(p4d_val(p4d) | RANDOM_ORVALUE);
-	WRITE_ONCE(*p4dp, p4d);
-	p4d_clear(p4dp);
-	p4d = READ_ONCE(*p4dp);
+	WRITE_ONCE(*(debug->p4dp), p4d);
+	p4d_clear(debug->p4dp);
+	p4d = READ_ONCE(*(debug->p4dp));
 	WARN_ON(!p4d_none(p4d));
 }
 
-static void __init p4d_populate_tests(struct mm_struct *mm, p4d_t *p4dp,
-				      pud_t *pudp)
+static void __init p4d_populate_tests(struct vm_pgtable_debug *debug)
 {
 	p4d_t p4d;
 
-	if (mm_pud_folded(mm))
+	if (mm_pud_folded(debug->mm))
 		return;
 
 	pr_debug("Validating P4D populate\n");
@@ -548,34 +547,33 @@ static void __init p4d_populate_tests(struct mm_struct *mm, p4d_t *p4dp,
 	 * This entry points to next level page table page.
 	 * Hence this must not qualify as p4d_bad().
 	 */
-	pud_clear(pudp);
-	p4d_clear(p4dp);
-	p4d_populate(mm, p4dp, pudp);
-	p4d = READ_ONCE(*p4dp);
+	pud_clear(debug->pudp);
+	p4d_clear(debug->p4dp);
+	p4d_populate(debug->mm, debug->p4dp, debug->start_pudp);
+	p4d = READ_ONCE(*(debug->p4dp));
 	WARN_ON(p4d_bad(p4d));
 }
 
-static void __init pgd_clear_tests(struct mm_struct *mm, pgd_t *pgdp)
+static void __init pgd_clear_tests(struct vm_pgtable_debug *debug)
 {
-	pgd_t pgd = READ_ONCE(*pgdp);
+	pgd_t pgd = READ_ONCE(*(debug->pgdp));
 
-	if (mm_p4d_folded(mm))
+	if (mm_p4d_folded(debug->mm))
 		return;
 
 	pr_debug("Validating PGD clear\n");
 	pgd = __pgd(pgd_val(pgd) | RANDOM_ORVALUE);
-	WRITE_ONCE(*pgdp, pgd);
-	pgd_clear(pgdp);
-	pgd = READ_ONCE(*pgdp);
+	WRITE_ONCE(*(debug->pgdp), pgd);
+	pgd_clear(debug->pgdp);
+	pgd = READ_ONCE(*(debug->pgdp));
 	WARN_ON(!pgd_none(pgd));
 }
 
-static void __init pgd_populate_tests(struct mm_struct *mm, pgd_t *pgdp,
-				      p4d_t *p4dp)
+static void __init pgd_populate_tests(struct vm_pgtable_debug *debug)
 {
 	pgd_t pgd;
 
-	if (mm_p4d_folded(mm))
+	if (mm_p4d_folded(debug->mm))
 		return;
 
 	pr_debug("Validating PGD populate\n");
@@ -583,23 +581,17 @@ static void __init pgd_populate_tests(struct mm_struct *mm, pgd_t *pgdp,
 	 * This entry points to next level page table page.
 	 * Hence this must not qualify as pgd_bad().
 	 */
-	p4d_clear(p4dp);
-	pgd_clear(pgdp);
-	pgd_populate(mm, pgdp, p4dp);
-	pgd = READ_ONCE(*pgdp);
+	p4d_clear(debug->p4dp);
+	pgd_clear(debug->pgdp);
+	pgd_populate(debug->mm, debug->pgdp, debug->start_p4dp);
+	pgd = READ_ONCE(*(debug->pgdp));
 	WARN_ON(pgd_bad(pgd));
 }
 #else  /* !__PAGETABLE_P4D_FOLDED */
-static void __init p4d_clear_tests(struct mm_struct *mm, p4d_t *p4dp) { }
-static void __init pgd_clear_tests(struct mm_struct *mm, pgd_t *pgdp) { }
-static void __init p4d_populate_tests(struct mm_struct *mm, p4d_t *p4dp,
-				      pud_t *pudp)
-{
-}
-static void __init pgd_populate_tests(struct mm_struct *mm, pgd_t *pgdp,
-				      p4d_t *p4dp)
-{
-}
+static void __init p4d_clear_tests(struct vm_pgtable_debug *debug) { }
+static void __init pgd_clear_tests(struct vm_pgtable_debug *debug) { }
+static void __init p4d_populate_tests(struct vm_pgtable_debug *debug) { }
+static void __init pgd_populate_tests(struct vm_pgtable_debug *debug) { }
 #endif /* PAGETABLE_P4D_FOLDED */
 
 static void __init pte_clear_tests(struct vm_pgtable_debug *debug)
@@ -1300,12 +1292,12 @@ static int __init debug_vm_pgtable(void)
 	pud_populate_tests(&debug);
 	spin_unlock(ptl);
 
-	spin_lock(&mm->page_table_lock);
-	p4d_clear_tests(mm, p4dp);
-	pgd_clear_tests(mm, pgdp);
-	p4d_populate_tests(mm, p4dp, saved_pudp);
-	pgd_populate_tests(mm, pgdp, saved_p4dp);
-	spin_unlock(&mm->page_table_lock);
+	spin_lock(&(debug.mm->page_table_lock));
+	p4d_clear_tests(&debug);
+	pgd_clear_tests(&debug);
+	p4d_populate_tests(&debug);
+	pgd_populate_tests(&debug);
+	spin_unlock(&(debug.mm->page_table_lock));
 
 	p4d_free(mm, saved_p4dp);
 	pud_free(mm, saved_pudp);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 11/12] mm/debug_vm_pgtable: Remove unused code
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (9 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 10/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PGD and P4D " Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-06  6:17 ` [PATCH 12/12] mm/debug_vm_pgtable: Fix corrupted page flag Gavin Shan
  2021-07-12  4:14 ` [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Anshuman Khandual
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

The variables used by old implementation isn't needed as we switched
to "struct vm_pgtable_debug". Lets just remove them.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 99 +++----------------------------------------
 1 file changed, 6 insertions(+), 93 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 7bc26808033c..1fd6d73d2152 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -32,14 +32,6 @@
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
-/*
- * Please refer Documentation/vm/arch_pgtable_helpers.rst for the semantics
- * expectations that are being validated here. All future changes in here
- * or the documentation need to be in sync.
- */
-
-#define VMFLAGS	(VM_READ|VM_WRITE|VM_EXEC)
-
 /*
  * On s390 platform, the lower 4 bits are used to identify given page table
  * entry type. But these bits might affect the ability to clear entries with
@@ -1025,7 +1017,12 @@ static int __init alloc_mem(struct vm_pgtable_debug *debug)
 	phys_addr_t phys;
 	int ret = 0;
 
-	/* Initialize the debugging data */
+	/*
+	 * Initialize the debugging data. For @page_prot, please refer
+	 * Documentation/vm/arch_pgtable_helpers.rst for the semantics
+	 * expectations that are being validated here. All future changes
+	 * in here or the documentation need to be in sync.
+	 */
 	debug->mm             = NULL;
 	debug->vma            = NULL;
 	debug->pgdp           = NULL;
@@ -1137,17 +1134,6 @@ static int __init alloc_mem(struct vm_pgtable_debug *debug)
 static int __init debug_vm_pgtable(void)
 {
 	struct vm_pgtable_debug debug;
-	struct vm_area_struct *vma;
-	struct mm_struct *mm;
-	pgd_t *pgdp;
-	p4d_t *p4dp, *saved_p4dp;
-	pud_t *pudp, *saved_pudp;
-	pmd_t *pmdp, *saved_pmdp, pmd;
-	pgtable_t saved_ptep;
-	pgprot_t prot, protnone;
-	phys_addr_t paddr;
-	unsigned long vaddr, pte_aligned, pmd_aligned;
-	unsigned long pud_aligned, p4d_aligned, pgd_aligned;
 	spinlock_t *ptl = NULL;
 	int idx, ret;
 
@@ -1156,68 +1142,6 @@ static int __init debug_vm_pgtable(void)
 	if (ret)
 		return ret;
 
-	prot = vm_get_page_prot(VMFLAGS);
-	vaddr = get_random_vaddr();
-	mm = mm_alloc();
-	if (!mm) {
-		pr_err("mm_struct allocation failed\n");
-		return 1;
-	}
-
-	/*
-	 * __P000 (or even __S000) will help create page table entries with
-	 * PROT_NONE permission as required for pxx_protnone_tests().
-	 */
-	protnone = __P000;
-
-	vma = vm_area_alloc(mm);
-	if (!vma) {
-		pr_err("vma allocation failed\n");
-		return 1;
-	}
-
-	/*
-	 * PFN for mapping at PTE level is determined from a standard kernel
-	 * text symbol. But pfns for higher page table levels are derived by
-	 * masking lower bits of this real pfn. These derived pfns might not
-	 * exist on the platform but that does not really matter as pfn_pxx()
-	 * helpers will still create appropriate entries for the test. This
-	 * helps avoid large memory block allocations to be used for mapping
-	 * at higher page table levels.
-	 */
-	paddr = __pa_symbol(&start_kernel);
-
-	pte_aligned = (paddr & PAGE_MASK) >> PAGE_SHIFT;
-	pmd_aligned = (paddr & PMD_MASK) >> PAGE_SHIFT;
-	pud_aligned = (paddr & PUD_MASK) >> PAGE_SHIFT;
-	p4d_aligned = (paddr & P4D_MASK) >> PAGE_SHIFT;
-	pgd_aligned = (paddr & PGDIR_MASK) >> PAGE_SHIFT;
-	WARN_ON(!pfn_valid(pte_aligned));
-
-	pgdp = pgd_offset(mm, vaddr);
-	p4dp = p4d_alloc(mm, pgdp, vaddr);
-	pudp = pud_alloc(mm, p4dp, vaddr);
-	pmdp = pmd_alloc(mm, pudp, vaddr);
-	/*
-	 * Allocate pgtable_t
-	 */
-	if (pte_alloc(mm, pmdp)) {
-		pr_err("pgtable allocation failed\n");
-		return 1;
-	}
-
-	/*
-	 * Save all the page table page addresses as the page table
-	 * entries will be used for testing with random or garbage
-	 * values. These saved addresses will be used for freeing
-	 * page table pages.
-	 */
-	pmd = READ_ONCE(*pmdp);
-	saved_p4dp = p4d_offset(pgdp, 0UL);
-	saved_pudp = pud_offset(p4dp, 0UL);
-	saved_pmdp = pmd_offset(pudp, 0UL);
-	saved_ptep = pmd_pgtable(pmd);
-
 	/*
 	 * Iterate over the protection_map[] to make sure that all
 	 * the basic page table transformation validations just hold
@@ -1299,17 +1223,6 @@ static int __init debug_vm_pgtable(void)
 	pgd_populate_tests(&debug);
 	spin_unlock(&(debug.mm->page_table_lock));
 
-	p4d_free(mm, saved_p4dp);
-	pud_free(mm, saved_pudp);
-	pmd_free(mm, saved_pmdp);
-	pte_free(mm, saved_ptep);
-
-	vm_area_free(vma);
-	mm_dec_nr_puds(mm);
-	mm_dec_nr_pmds(mm);
-	mm_dec_nr_ptes(mm);
-	mmdrop(mm);
-
 	free_mem(&debug);
 	return 0;
 }
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 12/12] mm/debug_vm_pgtable: Fix corrupted page flag
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (10 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 11/12] mm/debug_vm_pgtable: Remove unused code Gavin Shan
@ 2021-07-06  6:17 ` Gavin Shan
  2021-07-12  4:14 ` [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Anshuman Khandual
  12 siblings, 0 replies; 23+ messages in thread
From: Gavin Shan @ 2021-07-06  6:17 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, anshuman.khandual, catalin.marinas, will, akpm,
	shan.gavin, chuhu

In page table entry modifying tests, set_{pud, pmd, pte}_at() are
used to populate the page table entries. On ARM64, PG_arch_1 is
set to the target page flag if execution permission is given. The
page flag is kept when the page is free'd to buddy's free area
list. However, it will trigger page checking failure when it's
pulled from the buddy's free area list, as the following warning
messages indicate.

   BUG: Bad page state in process memhog  pfn:08000
   page:0000000015c0a628 refcount:0 mapcount:0 \
        mapping:0000000000000000 index:0x1 pfn:0x8000
   flags: 0x7ffff8000000800(arch_1|node=0|zone=0|lastcpupid=0xfffff)
   raw: 07ffff8000000800 dead000000000100 dead000000000122 0000000000000000
   raw: 0000000000000001 0000000000000000 00000000ffffffff 0000000000000000
   page dumped because: PAGE_FLAGS_CHECK_AT_PREP flag(s) set

This fixes the issue by clearing PG_arch_1 through flush_dcache_page(),
right after set_{pud, pmd, pte}_at() is called.

Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 1fd6d73d2152..de6f99382b4b 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -29,6 +29,8 @@
 #include <linux/start_kernel.h>
 #include <linux/sched/mm.h>
 #include <linux/io.h>
+
+#include <asm/cacheflush.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
@@ -110,6 +112,7 @@ static void __init pte_basic_tests(struct vm_pgtable_debug *debug, int idx)
 
 static void __init pte_advanced_tests(struct vm_pgtable_debug *debug)
 {
+	struct page *page;
 	pte_t pte;
 
 	/*
@@ -119,13 +122,17 @@ static void __init pte_advanced_tests(struct vm_pgtable_debug *debug)
 	 */
 
 	pr_debug("Validating PTE advanced\n");
-	if (debug->pte_pfn == ULONG_MAX) {
+
+	page = (debug->pte_pfn != ULONG_MAX) ?
+	       pfn_to_page(debug->pte_pfn) : NULL;
+	if (!page) {
 		pr_debug("%s: Skipped\n", __func__);
 		return;
 	}
 
 	pte = pfn_pte(debug->pte_pfn, debug->page_prot);
 	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
+	flush_dcache_page(page);
 	ptep_set_wrprotect(debug->mm, debug->vaddr, debug->ptep);
 	pte = ptep_get(debug->ptep);
 	WARN_ON(pte_write(pte));
@@ -137,6 +144,7 @@ static void __init pte_advanced_tests(struct vm_pgtable_debug *debug)
 	pte = pte_wrprotect(pte);
 	pte = pte_mkclean(pte);
 	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
+	flush_dcache_page(page);
 	pte = pte_mkwrite(pte);
 	pte = pte_mkdirty(pte);
 	ptep_set_access_flags(debug->vma, debug->vaddr, debug->ptep, pte, 1);
@@ -149,6 +157,7 @@ static void __init pte_advanced_tests(struct vm_pgtable_debug *debug)
 	pte = pfn_pte(debug->pte_pfn, debug->page_prot);
 	pte = pte_mkyoung(pte);
 	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
+	flush_dcache_page(page);
 	ptep_test_and_clear_young(debug->vma, debug->vaddr, debug->ptep);
 	pte = ptep_get(debug->ptep);
 	WARN_ON(pte_young(pte));
@@ -207,6 +216,7 @@ static void __init pmd_basic_tests(struct vm_pgtable_debug *debug, int idx)
 
 static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug)
 {
+	struct page *page;
 	pmd_t pmd;
 	unsigned long vaddr = (debug->vaddr & HPAGE_PMD_MASK);
 
@@ -214,7 +224,10 @@ static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug)
 		return;
 
 	pr_debug("Validating PMD advanced\n");
-	if (debug->pmd_pfn == ULONG_MAX) {
+
+	page = (debug->pmd_pfn != ULONG_MAX) ?
+	       pfn_to_page(debug->pmd_pfn) : NULL;
+	if (!page) {
 		pr_debug("%s: Skipped\n", __func__);
 		return;
 	}
@@ -223,6 +236,7 @@ static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug)
 
 	pmd = pfn_pmd(debug->pmd_pfn, debug->page_prot);
 	set_pmd_at(debug->mm, vaddr, debug->pmdp, pmd);
+	flush_dcache_page(page);
 	pmdp_set_wrprotect(debug->mm, vaddr, debug->pmdp);
 	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(pmd_write(pmd));
@@ -234,6 +248,7 @@ static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug)
 	pmd = pmd_wrprotect(pmd);
 	pmd = pmd_mkclean(pmd);
 	set_pmd_at(debug->mm, vaddr, debug->pmdp, pmd);
+	flush_dcache_page(page);
 	pmd = pmd_mkwrite(pmd);
 	pmd = pmd_mkdirty(pmd);
 	pmdp_set_access_flags(debug->vma, vaddr, debug->pmdp, pmd, 1);
@@ -246,6 +261,7 @@ static void __init pmd_advanced_tests(struct vm_pgtable_debug *debug)
 	pmd = pmd_mkhuge(pfn_pmd(debug->pmd_pfn, debug->page_prot));
 	pmd = pmd_mkyoung(pmd);
 	set_pmd_at(debug->mm, vaddr, debug->pmdp, pmd);
+	flush_dcache_page(page);
 	pmdp_test_and_clear_young(debug->vma, vaddr, debug->pmdp);
 	pmd = READ_ONCE(*(debug->pmdp));
 	WARN_ON(pmd_young(pmd));
@@ -332,6 +348,7 @@ static void __init pud_basic_tests(struct vm_pgtable_debug *debug, int idx)
 
 static void __init pud_advanced_tests(struct vm_pgtable_debug *debug)
 {
+	struct page *page;
 	unsigned long vaddr = (debug->vaddr & HPAGE_PUD_MASK);
 	pud_t pud;
 
@@ -339,13 +356,17 @@ static void __init pud_advanced_tests(struct vm_pgtable_debug *debug)
 		return;
 
 	pr_debug("Validating PUD advanced\n");
-	if (debug->pud_pfn == ULONG_MAX) {
+
+	page = (debug->pud_pfn != ULONG_MAX) ?
+	       pfn_to_page(debug->pud_pfn) : NULL;
+	if (!page) {
 		pr_debug("%s: Skipped\n", __func__);
 		return;
 	}
 
 	pud = pfn_pud(debug->pud_pfn, debug->page_prot);
 	set_pud_at(debug->mm, vaddr, debug->pudp, pud);
+	flush_dcache_page(page);
 	pudp_set_wrprotect(debug->mm, vaddr, debug->pudp);
 	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(pud_write(pud));
@@ -359,6 +380,7 @@ static void __init pud_advanced_tests(struct vm_pgtable_debug *debug)
 	pud = pud_wrprotect(pud);
 	pud = pud_mkclean(pud);
 	set_pud_at(debug->mm, vaddr, debug->pudp, pud);
+	flush_dcache_page(page);
 	pud = pud_mkwrite(pud);
 	pud = pud_mkdirty(pud);
 	pudp_set_access_flags(debug->vma, vaddr, debug->pudp, pud, 1);
@@ -374,6 +396,7 @@ static void __init pud_advanced_tests(struct vm_pgtable_debug *debug)
 	pud = pfn_pud(debug->pud_pfn, debug->page_prot);
 	pud = pud_mkyoung(pud);
 	set_pud_at(debug->mm, vaddr, debug->pudp, pud);
+	flush_dcache_page(page);
 	pudp_test_and_clear_young(debug->vma, vaddr, debug->pudp);
 	pud = READ_ONCE(*(debug->pudp));
 	WARN_ON(pud_young(pud));
@@ -588,10 +611,14 @@ static void __init pgd_populate_tests(struct vm_pgtable_debug *debug) { }
 
 static void __init pte_clear_tests(struct vm_pgtable_debug *debug)
 {
+	struct page *page;
 	pte_t pte;
 
 	pr_debug("Validating PTE clear\n");
-	if (debug->pte_pfn == ULONG_MAX) {
+
+	page = (debug->pte_pfn != ULONG_MAX) ?
+	       pfn_to_page(debug->pte_pfn) : NULL;
+	if (!page) {
 		pr_debug("%s: Skipped\n", __func__);
 		return;
 	}
@@ -601,6 +628,7 @@ static void __init pte_clear_tests(struct vm_pgtable_debug *debug)
 	pte = __pte(pte_val(pte) | RANDOM_ORVALUE);
 #endif
 	set_pte_at(debug->mm, debug->vaddr, debug->ptep, pte);
+	flush_dcache_page(page);
 	barrier();
 	pte_clear(debug->mm, debug->vaddr, debug->ptep);
 	pte = ptep_get(debug->ptep);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 00/12] mm/debug_vm_pgtable: Enhancements
  2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
                   ` (11 preceding siblings ...)
  2021-07-06  6:17 ` [PATCH 12/12] mm/debug_vm_pgtable: Fix corrupted page flag Gavin Shan
@ 2021-07-12  4:14 ` Anshuman Khandual
  2021-07-13  1:20   ` Gavin Shan
  12 siblings, 1 reply; 23+ messages in thread
From: Anshuman Khandual @ 2021-07-12  4:14 UTC (permalink / raw)
  To: Gavin Shan, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu

Hi Gavin,

Though I have not jumped into the details for all individual
patches here but still have some high level questions below.

On 7/6/21 11:47 AM, Gavin Shan wrote:
> There are couple of issues with current implementations and this series
> tries to resolve the issues:
> 
>   (a) All needed information are scattered in variables, passed to various
>       test functions. The code is organized in pretty much relaxed fashion.
All these variables are first prepared in debug_vm_pgtable(), before
getting passed into respective individual test functions. Also these
test functions receive only the required number of variables not all.
Adding a structure that captures all test parameters at once before
passing them down will be unnecessary. I am still wondering what will
be the real benefit of this large code churn ?

> 
>   (b) The page isn't allocated from buddy during page table entry modifying
>       tests. The page can be invalid, conflicting to the implementations
>       of set_{pud, pmd, pte}_at() on ARM64. The target page is accessed
>       so that the iCache can be flushed when execution permission is given
>       on ARM64. Besides, the target page can be unmapped and access to
>       it causes kernel crash.

Using 'start_kernel' based method for struct page usage, enabled this
test to run on platforms which might not have enough memory required
for various individual test functions. This method is not a problem for
tests that just need an aligned pfn (which creates a page table entry)
not a real struct page.

But not allocating and owning the struct page might be problematic for
tests that expect a real struct page and transform its state via set_
{pud, pmd, pte}_at() functions as reported here.

> 
> "struct vm_pgtable_debug" is introduced to address issue (a). For issue
> (b), the used page is allocated from buddy in page table entry modifying
> tests. The corresponding tets will be skipped if we fail to allocate the
> (huge) page. For other test cases, the original page around to kernel
> symbol (@start_kernel) is still used.

For all basic pfn requiring tests, existing 'start_kernel' based method
should continue but allocate a struct page for other tests which change
the passed struct page. Skipping the tests when allocation fails is the
right thing to do.

- Anshuman

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 00/12] mm/debug_vm_pgtable: Enhancements
  2021-07-12  4:14 ` [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Anshuman Khandual
@ 2021-07-13  1:20   ` Gavin Shan
  2021-07-14  5:26     ` Anshuman Khandual
  0 siblings, 1 reply; 23+ messages in thread
From: Gavin Shan @ 2021-07-13  1:20 UTC (permalink / raw)
  To: Anshuman Khandual, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu

Hi Anshuman,

On 7/12/21 2:14 PM, Anshuman Khandual wrote:
> Though I have not jumped into the details for all individual
> patches here but still have some high level questions below.
> 
> On 7/6/21 11:47 AM, Gavin Shan wrote:
>> There are couple of issues with current implementations and this series
>> tries to resolve the issues:
>>
>>    (a) All needed information are scattered in variables, passed to various
>>        test functions. The code is organized in pretty much relaxed fashion.
> All these variables are first prepared in debug_vm_pgtable(), before
> getting passed into respective individual test functions. Also these
> test functions receive only the required number of variables not all.
> Adding a structure that captures all test parameters at once before
> passing them down will be unnecessary. I am still wondering what will
> be the real benefit of this large code churn ?
> 

Thanks for your review. There are couple of reasons to have "struct vm_pgtable_debug".

(1) With the struct, the old and new implementation can coexist. In this way,
     the patches in this series can be stacked up easily.
(2) I think passing single struct to individual test functions improves the
     code readability. Besides, it also makes the empty stubs simplified.
(3) The code can be extended easily if we need in future.

>>
>>    (b) The page isn't allocated from buddy during page table entry modifying
>>        tests. The page can be invalid, conflicting to the implementations
>>        of set_{pud, pmd, pte}_at() on ARM64. The target page is accessed
>>        so that the iCache can be flushed when execution permission is given
>>        on ARM64. Besides, the target page can be unmapped and access to
>>        it causes kernel crash.
> 
> Using 'start_kernel' based method for struct page usage, enabled this
> test to run on platforms which might not have enough memory required
> for various individual test functions. This method is not a problem for
> tests that just need an aligned pfn (which creates a page table entry)
> not a real struct page.
> 
> But not allocating and owning the struct page might be problematic for
> tests that expect a real struct page and transform its state via set_
> {pud, pmd, pte}_at() functions as reported here.
> 

Yeah, I totally agree. The series follows what you explained: Except the
test cases where set_{pud, pmd, pte}_at() is used, the allocated page
is used. For other test cases, 'start_kernel' based PFN is used as before.

>>
>> "struct vm_pgtable_debug" is introduced to address issue (a). For issue
>> (b), the used page is allocated from buddy in page table entry modifying
>> tests. The corresponding tets will be skipped if we fail to allocate the
>> (huge) page. For other test cases, the original page around to kernel
>> symbol (@start_kernel) is still used.
> 
> For all basic pfn requiring tests, existing 'start_kernel' based method
> should continue but allocate a struct page for other tests which change
> the passed struct page. Skipping the tests when allocation fails is the
> right thing to do.
> 

Yes, it's exactly what this series does. Hope you can jump into the details
when you get a chance :)

Thanks,
Gavin


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 00/12] mm/debug_vm_pgtable: Enhancements
  2021-07-13  1:20   ` Gavin Shan
@ 2021-07-14  5:26     ` Anshuman Khandual
  2021-07-15  5:17       ` Gavin Shan
  0 siblings, 1 reply; 23+ messages in thread
From: Anshuman Khandual @ 2021-07-14  5:26 UTC (permalink / raw)
  To: Gavin Shan, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu



On 7/13/21 6:50 AM, Gavin Shan wrote:
> Hi Anshuman,
> 
> On 7/12/21 2:14 PM, Anshuman Khandual wrote:
>> Though I have not jumped into the details for all individual
>> patches here but still have some high level questions below.
>>
>> On 7/6/21 11:47 AM, Gavin Shan wrote:
>>> There are couple of issues with current implementations and this series
>>> tries to resolve the issues:
>>>
>>>    (a) All needed information are scattered in variables, passed to various
>>>        test functions. The code is organized in pretty much relaxed fashion.
>> All these variables are first prepared in debug_vm_pgtable(), before
>> getting passed into respective individual test functions. Also these
>> test functions receive only the required number of variables not all.
>> Adding a structure that captures all test parameters at once before
>> passing them down will be unnecessary. I am still wondering what will
>> be the real benefit of this large code churn ?
>>
> 
> Thanks for your review. There are couple of reasons to have "struct vm_pgtable_debug".
> 
> (1) With the struct, the old and new implementation can coexist. In this way,
>     the patches in this series can be stacked up easily.

Makes sense.

> (2) I think passing single struct to individual test functions improves the
>     code readability. Besides, it also makes the empty stubs simplified.

Empty stub simplified - reduced argument set in the empty stubs ?

> (3) The code can be extended easily if we need in future.

Agreed.

> 
>>>
>>>    (b) The page isn't allocated from buddy during page table entry modifying
>>>        tests. The page can be invalid, conflicting to the implementations
>>>        of set_{pud, pmd, pte}_at() on ARM64. The target page is accessed
>>>        so that the iCache can be flushed when execution permission is given
>>>        on ARM64. Besides, the target page can be unmapped and access to
>>>        it causes kernel crash.
>>
>> Using 'start_kernel' based method for struct page usage, enabled this
>> test to run on platforms which might not have enough memory required
>> for various individual test functions. This method is not a problem for
>> tests that just need an aligned pfn (which creates a page table entry)
>> not a real struct page.
>>
>> But not allocating and owning the struct page might be problematic for
>> tests that expect a real struct page and transform its state via set_
>> {pud, pmd, pte}_at() functions as reported here.
>>
> 
> Yeah, I totally agree. The series follows what you explained: Except the
> test cases where set_{pud, pmd, pte}_at() is used, the allocated page
> is used. For other test cases, 'start_kernel' based PFN is used as before.
> 
>>>
>>> "struct vm_pgtable_debug" is introduced to address issue (a). For issue
>>> (b), the used page is allocated from buddy in page table entry modifying
>>> tests. The corresponding tets will be skipped if we fail to allocate the
>>> (huge) page. For other test cases, the original page around to kernel
>>> symbol (@start_kernel) is still used.
>>
>> For all basic pfn requiring tests, existing 'start_kernel' based method
>> should continue but allocate a struct page for other tests which change
>> the passed struct page. Skipping the tests when allocation fails is the
>> right thing to do.
>>
> 
> Yes, it's exactly what this series does. Hope you can jump into the details
> when you get a chance :)

I have already started looking into the series. But still wondering if
the huge page memory allocation change and the arm64 specific page fix
should be completed first, before getting into the new structure based
arguments (in a separate series). Although the end result would still
remain the same, the transition there would be better I guess. Do you
see any challenges in achieving that ?

- Anshuman

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug
  2021-07-06  6:17 ` [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug Gavin Shan
@ 2021-07-14  6:24   ` Anshuman Khandual
  2021-07-19  5:39     ` Gavin Shan
  0 siblings, 1 reply; 23+ messages in thread
From: Anshuman Khandual @ 2021-07-14  6:24 UTC (permalink / raw)
  To: Gavin Shan, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu


On 7/6/21 11:47 AM, Gavin Shan wrote:
> In debug_vm_pgtable(), there are many local variables introduced
> to track the needed information and they are passed to the functions
> for various test cases. It'd better to introduce a struct as place
> holder for these information. With it, what the functions for various
> test cases need is the struct, to simplify the code. It makes the code
> easier to be maintained.
> 
> Besides, set_pte_at() could access the data on the corresponding pages.

s/set_pte_at()/set_pxx_at() to accommodate similar helpers in other page
table modifying tests as well.

> So the test cases using set_pte_at() should have the pages allocated
> from buddy. Otherwise, we're acceessing pages that aren't owned by us.

typo here. s/acceessing/accessing/

> This causes issues like page flag corruption. So we need the allocated
> pages for these tests where set_pte_at() is used. The struct is introduced
> so that the old and new implementation can coexist so that the patches
> can be organized in a easy way.

s/a easy/an easy/

The rationale for the structure should be explained better. I am wondering
whether it would be preferable to solve the dynamic page allocation problem
first in respective test functions, before introducing this structure which
will convert all test functions.

> 
> This introduces "struct vm_pgtable_debug" for above purposes. The struct
> is initialized and destroyed, but the information in the struct isn't
> used yet. They will be used in subsequent patches.

There are two set of resources before all functions use the new structure.
Makes sense.

> 
> Signed-off-by: Gavin Shan <gshan@redhat.com>
> ---
>  mm/debug_vm_pgtable.c | 210 +++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 209 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
> index 1c922691aa61..225e2ea4d72f 100644
> --- a/mm/debug_vm_pgtable.c
> +++ b/mm/debug_vm_pgtable.c
> @@ -58,6 +58,36 @@
>  #define RANDOM_ORVALUE (GENMASK(BITS_PER_LONG - 1, 0) & ~ARCH_SKIP_MASK)
>  #define RANDOM_NZVALUE	GENMASK(7, 0)
>  
> +struct vm_pgtable_debug {

Name should contain 'args'. Probably something like pgtable_debug_args ?

> +	struct mm_struct	*mm;
> +	struct vm_area_struct	*vma;

Linked objects..

> +
> +	pgd_t			*pgdp;
> +	p4d_t			*p4dp;
> +	pud_t			*pudp;
> +	pmd_t			*pmdp;
> +	pte_t			*ptep;

pgtable pointers..

> +
> +	p4d_t			*start_p4dp;
> +	pud_t			*start_pudp;
> +	pmd_t			*start_pmdp;
> +	pgtable_t		start_ptep;

Saved pgtable pointers..

> +
> +	unsigned long		vaddr;
> +	pgprot_t		page_prot;
> +	pgprot_t		page_prot_none;

Other miscellaneous objects..

> +
> +	unsigned long		pud_pfn;
> +	unsigned long		pmd_pfn;
> +	unsigned long		pte_pfn;

Dynamically allocated objects..

> +
> +	unsigned long		fixed_pgd_pfn;
> +	unsigned long		fixed_p4d_pfn;
> +	unsigned long		fixed_pud_pfn;
> +	unsigned long		fixed_pmd_pfn;
> +	unsigned long		fixed_pte_pfn;
> +};

Derived from symbol 'start_kernel' objects..

> +
>  static void __init pte_basic_tests(unsigned long pfn, int idx)
>  {
>  	pgprot_t prot = protection_map[idx];
> @@ -955,8 +985,180 @@ static unsigned long __init get_random_vaddr(void)
>  	return random_vaddr;
>  }
>  
> +static void __init free_mem(struct vm_pgtable_debug *debug)
> +{
> +	struct page *page = NULL;
> +	int order = 0;
> +
> +	/* Free (huge) page */
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD

Replace #ifdef with IS_ENABLED(). There is no symbol visibility problem
without those #ifdef here.

> +	if (has_transparent_hugepage() &&
> +	    debug->pud_pfn != ULONG_MAX) {
> +		page = pfn_to_page(debug->pud_pfn);
> +		order = HPAGE_PUD_SHIFT - PAGE_SHIFT;
> +	}
> +#endif
> +
> +	if (has_transparent_hugepage() &&
> +	    debug->pmd_pfn != ULONG_MAX && !page) {
> +		page = pfn_to_page(debug->pmd_pfn);
> +		order = HPAGE_PMD_ORDER;
> +	}
> +#endif
> +
> +	if (debug->pte_pfn != ULONG_MAX && !page) {
> +		page = pfn_to_page(debug->pte_pfn);
> +		order = 0;
> +	}

This could be further simplified.

	if (debug->pud_pfn) {
		__free_pages(page, PUD_ORDER)
		done
	}

	if (debug->pmd_pfn) {
		__free_pages(page, PMD_ORDER)
		done
	}

	if (debug->pte_pfn)
		__free_pages(page, 0)

If the debug->pxx_pfn is positive and (!= ULONG_MAX), it can be assumed
that pxx level memory was allocated successfully and is being freed up
here. Just need to start from the highest order though.

> +
> +	if (page)
> +		__free_pages(page, order);

From here...

> +
> +	/* Free page table */
> +	if (debug->start_ptep) {
> +		pte_free(debug->mm, debug->start_ptep);
> +		mm_dec_nr_ptes(debug->mm);
> +	}
> +
> +	if (debug->start_pmdp) {
> +		pmd_free(debug->mm, debug->start_pmdp);
> +		mm_dec_nr_pmds(debug->mm);
> +	}
> +
> +	if (debug->start_pudp) {
> +		pud_free(debug->mm, debug->start_pudp);
> +		mm_dec_nr_puds(debug->mm);
> +	}
> +
> +	if (debug->start_p4dp)
> +		p4d_free(debug->mm, debug->p4dp);
> +
> +	/* Free vma and mm struct */
> +	if (debug->vma)
> +		vm_area_free(debug->vma);
> +	if (debug->mm)
> +		mmdrop(debug->mm);
> +}

Till here...

I am wondering whether it is really necessary to cross check all these
elements here for being non-NULL, before freeing or rather destroying.
Except for the allocated huge memory containing pfns and pages, all
other elements should be asserted before proceeding with the test.
Hence no additional checks should be required while freeing.

> +
> +static int __init alloc_mem(struct vm_pgtable_debug *debug)
> +{
> +	struct page *page = NULL;
> +	phys_addr_t phys;
> +	int ret = 0;
> +
> +	/* Initialize the debugging data */
> +	debug->mm             = NULL;
> +	debug->vma            = NULL;
> +	debug->pgdp           = NULL;
> +	debug->p4dp           = NULL;
> +	debug->pudp           = NULL;
> +	debug->pmdp           = NULL;
> +	debug->ptep           = NULL;
> +	debug->start_p4dp     = NULL;
> +	debug->start_pudp     = NULL;
> +	debug->start_pmdp     = NULL;
> +	debug->start_ptep     = NULL;
> +	debug->vaddr          = 0UL;
> +	debug->page_prot      = vm_get_page_prot(VM_READ | VM_WRITE | VM_EXEC);

Should use VMFLAGS instead.

> +	debug->page_prot_none = __P000;
> +	debug->pud_pfn        = ULONG_MAX;
> +	debug->pmd_pfn        = ULONG_MAX;
> +	debug->pte_pfn        = ULONG_MAX;
> +	debug->fixed_pgd_pfn  = ULONG_MAX;
> +	debug->fixed_p4d_pfn  = ULONG_MAX;
> +	debug->fixed_pud_pfn  = ULONG_MAX;
> +	debug->fixed_pmd_pfn  = ULONG_MAX;
> +	debug->fixed_pte_pfn  = ULONG_MAX;

It should instead define yet another helper, which would reset all
structure elements to NULL or some unusable values before they get
initialized here. Possibly [reset/clr]_debug_pgtable_args() ?

> +
> +	/* Allocate mm and vma */
> +	debug->mm = mm_alloc();
> +	if (!debug->mm) {
> +		pr_warn("Failed to allocate mm struct\n");
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	debug->vma = vm_area_alloc(debug->mm);
> +	if (!debug->vma) {
> +		pr_warn("Failed to allocate vma\n");

s/pr_warn/pr_err. Please dont change any warning levels here.

> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/* Figure out the virtual address and allocate page table entries */
> +	debug->vaddr = get_random_vaddr();
> +	debug->pgdp = pgd_offset(debug->mm, debug->vaddr);
> +	debug->p4dp = p4d_alloc(debug->mm, debug->pgdp, debug->vaddr);
> +	debug->pudp = debug->p4dp ?
> +		      pud_alloc(debug->mm, debug->p4dp, debug->vaddr) : NULL;
> +	debug->pmdp = debug->pudp ?
> +		      pmd_alloc(debug->mm, debug->pudp, debug->vaddr) : NULL;
> +	debug->ptep = debug->pmdp ?
> +		      pte_alloc_map(debug->mm, debug->pmdp, debug->vaddr) : NULL;

(PXXX ?) construct is really required here. Should not pxx_alloc()
return NULL if the previous level pointer is NULL ? Regardless it
might be better to just assert that these intermediary levels are
allocated before proceeding further. It does not make sense to go
ahead with the test if any of the allocations failed ! Similar to
mm and vma.


> +	if (!debug->ptep) {
> +		pr_warn("Failed to allocate page table\n");
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	/*
> +	 * The above page table entries will be modified. Lets save the
> +	 * page table entries so that they can be released when the tests
> +	 * are completed.
> +	 */
> +	debug->start_p4dp = p4d_offset(debug->pgdp, 0UL);
> +	debug->start_pudp = pud_offset(debug->p4dp, 0UL);
> +	debug->start_pmdp = pmd_offset(debug->pudp, 0UL);
> +	debug->start_ptep = pmd_pgtable(*(debug->pmdp));

Please keep the existing construct via tmp pointer obtained from
READ_ONCE() on (debug->pmdp) before getting used in pmd_pgtable().

> +
> +	/*
> +	 * Figure out the fixed addresses, which are all around the kernel
> +	 * symbol (@start_kernel). The corresponding PFNs might be invalid,
> +	 * but it's fine as the following tests won't access the pages.
> +	 */
> +	phys = __pa_symbol(&start_kernel);
> +	debug->fixed_pgd_pfn = __phys_to_pfn(phys & PGDIR_MASK);
> +	debug->fixed_p4d_pfn = __phys_to_pfn(phys & P4D_MASK);
> +	debug->fixed_pud_pfn = __phys_to_pfn(phys & PUD_MASK);
> +	debug->fixed_pmd_pfn = __phys_to_pfn(phys & PMD_MASK);
> +	debug->fixed_pte_pfn = __phys_to_pfn(phys & PAGE_MASK);
> +
> +	/*
> +	 * Allocate (huge) pages because some of the tests need to access
> +	 * the data in the pages. The corresponding tests will be skipped
> +	 * if we fail to allocate (huge) pages.
> +	 */
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD

There is no symbol visibility problem without this #ifdef. Hence
please use IS_ENABLED() constructs here instead.

> +	if (has_transparent_hugepage()) {
> +		page = alloc_pages(GFP_KERNEL, HPAGE_PUD_SHIFT - PAGE_SHIFT);
> +		if (page)
> +			debug->pud_pfn = page_to_pfn(page);
			debug->pmd_pfn = debug->pud_pfn;
			debug->pte_pfn = debug->pud_pfn;
			done; skip;
> +	}
> +#endif
> +
> +	if (has_transparent_hugepage()) {
> +		page = page ? page : alloc_pages(GFP_KERNEL, HPAGE_PMD_ORDER);
> +		if (page)
> +			debug->pmd_pfn = page_to_pfn(page);
			debug->pte_pfn = debug->pmd_pfn;
			done; skip;
> +	}
> +#endif
> +
> +	page = page ? page : alloc_pages(GFP_KERNEL, 0);
> +	if (page)
> +		debug->pte_pfn = page_to_pfn(page);

With the above mentioned changes (page ?) constructs should not be
required anymore.

> +
> +	return 0;
> +
> +error:
> +	free_mem(debug);
> +	return ret;
> +}
> +
>  static int __init debug_vm_pgtable(void)
>  {
> +	struct vm_pgtable_debug debug;

This should be renamed.

s/debug/pgtable_args ?

>  	struct vm_area_struct *vma;
>  	struct mm_struct *mm;
>  	pgd_t *pgdp;
> @@ -970,9 +1172,13 @@ static int __init debug_vm_pgtable(void)
>  	unsigned long vaddr, pte_aligned, pmd_aligned;
>  	unsigned long pud_aligned, p4d_aligned, pgd_aligned;
>  	spinlock_t *ptl = NULL;
> -	int idx;
> +	int idx, ret;
>  
>  	pr_info("Validating architecture page table helpers\n");
> +	ret = alloc_mem(&debug);
> +	if (ret)
> +		return ret;
> +
>  	prot = vm_get_page_prot(VMFLAGS);
>  	vaddr = get_random_vaddr();
>  	mm = mm_alloc();
> @@ -1127,6 +1333,8 @@ static int __init debug_vm_pgtable(void)
>  	mm_dec_nr_pmds(mm);
>  	mm_dec_nr_ptes(mm);
>  	mmdrop(mm);
> +
> +	free_mem(&debug);
>  	return 0;
>  }
>  late_initcall(debug_vm_pgtable);
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 00/12] mm/debug_vm_pgtable: Enhancements
  2021-07-14  5:26     ` Anshuman Khandual
@ 2021-07-15  5:17       ` Gavin Shan
  2021-07-18  6:36         ` Anshuman Khandual
  0 siblings, 1 reply; 23+ messages in thread
From: Gavin Shan @ 2021-07-15  5:17 UTC (permalink / raw)
  To: Anshuman Khandual, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu

Hi Anshuman,

On 7/14/21 3:26 PM, Anshuman Khandual wrote:
> On 7/13/21 6:50 AM, Gavin Shan wrote:
>> On 7/12/21 2:14 PM, Anshuman Khandual wrote:
>>> Though I have not jumped into the details for all individual
>>> patches here but still have some high level questions below.
>>>
>>> On 7/6/21 11:47 AM, Gavin Shan wrote:
>>>> There are couple of issues with current implementations and this series
>>>> tries to resolve the issues:
>>>>
>>>>     (a) All needed information are scattered in variables, passed to various
>>>>         test functions. The code is organized in pretty much relaxed fashion.
>>> All these variables are first prepared in debug_vm_pgtable(), before
>>> getting passed into respective individual test functions. Also these
>>> test functions receive only the required number of variables not all.
>>> Adding a structure that captures all test parameters at once before
>>> passing them down will be unnecessary. I am still wondering what will
>>> be the real benefit of this large code churn ?
>>>
>>
>> Thanks for your review. There are couple of reasons to have "struct vm_pgtable_debug".
>>
>> (1) With the struct, the old and new implementation can coexist. In this way,
>>      the patches in this series can be stacked up easily.
> 
> Makes sense.
> 
>> (2) I think passing single struct to individual test functions improves the
>>      code readability. Besides, it also makes the empty stubs simplified.
> 
> Empty stub simplified - reduced argument set in the empty stubs ?
> 

Yes.

>> (3) The code can be extended easily if we need in future.
> 
> Agreed.
> 
>>
>>>>
>>>>     (b) The page isn't allocated from buddy during page table entry modifying
>>>>         tests. The page can be invalid, conflicting to the implementations
>>>>         of set_{pud, pmd, pte}_at() on ARM64. The target page is accessed
>>>>         so that the iCache can be flushed when execution permission is given
>>>>         on ARM64. Besides, the target page can be unmapped and access to
>>>>         it causes kernel crash.
>>>
>>> Using 'start_kernel' based method for struct page usage, enabled this
>>> test to run on platforms which might not have enough memory required
>>> for various individual test functions. This method is not a problem for
>>> tests that just need an aligned pfn (which creates a page table entry)
>>> not a real struct page.
>>>
>>> But not allocating and owning the struct page might be problematic for
>>> tests that expect a real struct page and transform its state via set_
>>> {pud, pmd, pte}_at() functions as reported here.
>>>
>>
>> Yeah, I totally agree. The series follows what you explained: Except the
>> test cases where set_{pud, pmd, pte}_at() is used, the allocated page
>> is used. For other test cases, 'start_kernel' based PFN is used as before.
>>
>>>>
>>>> "struct vm_pgtable_debug" is introduced to address issue (a). For issue
>>>> (b), the used page is allocated from buddy in page table entry modifying
>>>> tests. The corresponding tets will be skipped if we fail to allocate the
>>>> (huge) page. For other test cases, the original page around to kernel
>>>> symbol (@start_kernel) is still used.
>>>
>>> For all basic pfn requiring tests, existing 'start_kernel' based method
>>> should continue but allocate a struct page for other tests which change
>>> the passed struct page. Skipping the tests when allocation fails is the
>>> right thing to do.
>>>
>>
>> Yes, it's exactly what this series does. Hope you can jump into the details
>> when you get a chance :)
> 
> I have already started looking into the series. But still wondering if
> the huge page memory allocation change and the arm64 specific page fix
> should be completed first, before getting into the new structure based
> arguments (in a separate series). Although the end result would still
> remain the same, the transition there would be better I guess. Do you
> see any challenges in achieving that ?
> 

Thanks for your time to review in details. As I can understand, the reason
to have the fix for easy backporting to stable-kernel and I didn't do that
because of couple of facts: (1) The changes included in this series only
affects only one source file, so backporting the whole series isn't hard.
(2) There will be more redundant code if we include the fix before switching
to "struct vm_pgtable_debug". It's unnecessary.

So lets keep the patch layout we had if you agree. Actually, the issues are
found during the testing with RHEL downstream kernel. Once it's settled down,
I will backport the whole series to RHEL downstream kernel.

Thanks,
Gavin


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 00/12] mm/debug_vm_pgtable: Enhancements
  2021-07-15  5:17       ` Gavin Shan
@ 2021-07-18  6:36         ` Anshuman Khandual
  0 siblings, 0 replies; 23+ messages in thread
From: Anshuman Khandual @ 2021-07-18  6:36 UTC (permalink / raw)
  To: Gavin Shan, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu



On 7/15/21 10:47 AM, Gavin Shan wrote:
> Hi Anshuman,
> 
> On 7/14/21 3:26 PM, Anshuman Khandual wrote:
>> On 7/13/21 6:50 AM, Gavin Shan wrote:
>>> On 7/12/21 2:14 PM, Anshuman Khandual wrote:
>>>> Though I have not jumped into the details for all individual
>>>> patches here but still have some high level questions below.
>>>>
>>>> On 7/6/21 11:47 AM, Gavin Shan wrote:
>>>>> There are couple of issues with current implementations and this series
>>>>> tries to resolve the issues:
>>>>>
>>>>>     (a) All needed information are scattered in variables, passed to various
>>>>>         test functions. The code is organized in pretty much relaxed fashion.
>>>> All these variables are first prepared in debug_vm_pgtable(), before
>>>> getting passed into respective individual test functions. Also these
>>>> test functions receive only the required number of variables not all.
>>>> Adding a structure that captures all test parameters at once before
>>>> passing them down will be unnecessary. I am still wondering what will
>>>> be the real benefit of this large code churn ?
>>>>
>>>
>>> Thanks for your review. There are couple of reasons to have "struct vm_pgtable_debug".
>>>
>>> (1) With the struct, the old and new implementation can coexist. In this way,
>>>      the patches in this series can be stacked up easily.
>>
>> Makes sense.
>>
>>> (2) I think passing single struct to individual test functions improves the
>>>      code readability. Besides, it also makes the empty stubs simplified.
>>
>> Empty stub simplified - reduced argument set in the empty stubs ?
>>
> 
> Yes.
> 
>>> (3) The code can be extended easily if we need in future.
>>
>> Agreed.
>>
>>>
>>>>>
>>>>>     (b) The page isn't allocated from buddy during page table entry modifying
>>>>>         tests. The page can be invalid, conflicting to the implementations
>>>>>         of set_{pud, pmd, pte}_at() on ARM64. The target page is accessed
>>>>>         so that the iCache can be flushed when execution permission is given
>>>>>         on ARM64. Besides, the target page can be unmapped and access to
>>>>>         it causes kernel crash.
>>>>
>>>> Using 'start_kernel' based method for struct page usage, enabled this
>>>> test to run on platforms which might not have enough memory required
>>>> for various individual test functions. This method is not a problem for
>>>> tests that just need an aligned pfn (which creates a page table entry)
>>>> not a real struct page.
>>>>
>>>> But not allocating and owning the struct page might be problematic for
>>>> tests that expect a real struct page and transform its state via set_
>>>> {pud, pmd, pte}_at() functions as reported here.
>>>>
>>>
>>> Yeah, I totally agree. The series follows what you explained: Except the
>>> test cases where set_{pud, pmd, pte}_at() is used, the allocated page
>>> is used. For other test cases, 'start_kernel' based PFN is used as before.
>>>
>>>>>
>>>>> "struct vm_pgtable_debug" is introduced to address issue (a). For issue
>>>>> (b), the used page is allocated from buddy in page table entry modifying
>>>>> tests. The corresponding tets will be skipped if we fail to allocate the
>>>>> (huge) page. For other test cases, the original page around to kernel
>>>>> symbol (@start_kernel) is still used.
>>>>
>>>> For all basic pfn requiring tests, existing 'start_kernel' based method
>>>> should continue but allocate a struct page for other tests which change
>>>> the passed struct page. Skipping the tests when allocation fails is the
>>>> right thing to do.
>>>>
>>>
>>> Yes, it's exactly what this series does. Hope you can jump into the details
>>> when you get a chance :)
>>
>> I have already started looking into the series. But still wondering if
>> the huge page memory allocation change and the arm64 specific page fix
>> should be completed first, before getting into the new structure based
>> arguments (in a separate series). Although the end result would still
>> remain the same, the transition there would be better I guess. Do you
>> see any challenges in achieving that ?
>>
> 
> Thanks for your time to review in details. As I can understand, the reason
> to have the fix for easy backporting to stable-kernel and I didn't do that
> because of couple of facts: (1) The changes included in this series only
> affects only one source file, so backporting the whole series isn't hard.
> (2) There will be more redundant code if we include the fix before switching
> to "struct vm_pgtable_debug". It's unnecessary.

Okay.

> 
> So lets keep the patch layout we had if you agree. Actually, the issues are
> found during the testing with RHEL downstream kernel. Once it's settled down,
> I will backport the whole series to RHEL downstream kernel.

Okay, then lets keep this proposed layout and address the issues here.

- Anshuman

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug
  2021-07-14  6:24   ` Anshuman Khandual
@ 2021-07-19  5:39     ` Gavin Shan
  2021-07-20  7:02       ` Anshuman Khandual
  0 siblings, 1 reply; 23+ messages in thread
From: Gavin Shan @ 2021-07-19  5:39 UTC (permalink / raw)
  To: Anshuman Khandual, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu

Hi Anshuman,

On 7/14/21 4:24 PM, Anshuman Khandual wrote:
> On 7/6/21 11:47 AM, Gavin Shan wrote:

Thanks for your review. I will take all your suggestion if it's applicable.
Otherwise, I will explain as below. All changes will be included in v2,
which will be posted pretty soon.

>> In debug_vm_pgtable(), there are many local variables introduced
>> to track the needed information and they are passed to the functions
>> for various test cases. It'd better to introduce a struct as place
>> holder for these information. With it, what the functions for various
>> test cases need is the struct, to simplify the code. It makes the code
>> easier to be maintained.
>>
>> Besides, set_pte_at() could access the data on the corresponding pages.
> 
> s/set_pte_at()/set_pxx_at() to accommodate similar helpers in other page
> table modifying tests as well.
> 

Ok.

>> So the test cases using set_pte_at() should have the pages allocated
>> from buddy. Otherwise, we're acceessing pages that aren't owned by us.
> 
> typo here. s/acceessing/accessing/
> 

Ok.

>> This causes issues like page flag corruption. So we need the allocated
>> pages for these tests where set_pte_at() is used. The struct is introduced
>> so that the old and new implementation can coexist so that the patches
>> can be organized in a easy way.
> 
> s/a easy/an easy/
> 

Ok.

> The rationale for the structure should be explained better. I am wondering
> whether it would be preferable to solve the dynamic page allocation problem
> first in respective test functions, before introducing this structure which
> will convert all test functions.
> 
>>
>> This introduces "struct vm_pgtable_debug" for above purposes. The struct
>> is initialized and destroyed, but the information in the struct isn't
>> used yet. They will be used in subsequent patches.
> 
> There are two set of resources before all functions use the new structure.
> Makes sense.
> 
>>
>> Signed-off-by: Gavin Shan <gshan@redhat.com>
>> ---
>>   mm/debug_vm_pgtable.c | 210 +++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 209 insertions(+), 1 deletion(-)
>>
>> diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
>> index 1c922691aa61..225e2ea4d72f 100644
>> --- a/mm/debug_vm_pgtable.c
>> +++ b/mm/debug_vm_pgtable.c
>> @@ -58,6 +58,36 @@
>>   #define RANDOM_ORVALUE (GENMASK(BITS_PER_LONG - 1, 0) & ~ARCH_SKIP_MASK)
>>   #define RANDOM_NZVALUE	GENMASK(7, 0)
>>   
>> +struct vm_pgtable_debug {
> 
> Name should contain 'args'. Probably something like pgtable_debug_args ?
> 

Sure, It will be "struct pgtable_debug_args" and the parameter name
to various test functions will be "@args".

>> +	struct mm_struct	*mm;
>> +	struct vm_area_struct	*vma;
> 
> Linked objects..
> 
>> +
>> +	pgd_t			*pgdp;
>> +	p4d_t			*p4dp;
>> +	pud_t			*pudp;
>> +	pmd_t			*pmdp;
>> +	pte_t			*ptep;
> 
> pgtable pointers..
> 
>> +
>> +	p4d_t			*start_p4dp;
>> +	pud_t			*start_pudp;
>> +	pmd_t			*start_pmdp;
>> +	pgtable_t		start_ptep;
> 
> Saved pgtable pointers..
> 
>> +
>> +	unsigned long		vaddr;
>> +	pgprot_t		page_prot;
>> +	pgprot_t		page_prot_none;
> 
> Other miscellaneous objects..
> 
>> +
>> +	unsigned long		pud_pfn;
>> +	unsigned long		pmd_pfn;
>> +	unsigned long		pte_pfn;
> 
> Dynamically allocated objects..
> 
>> +
>> +	unsigned long		fixed_pgd_pfn;
>> +	unsigned long		fixed_p4d_pfn;
>> +	unsigned long		fixed_pud_pfn;
>> +	unsigned long		fixed_pmd_pfn;
>> +	unsigned long		fixed_pte_pfn;
>> +};
> 
> Derived from symbol 'start_kernel' objects..
> 
>> +
>>   static void __init pte_basic_tests(unsigned long pfn, int idx)
>>   {
>>   	pgprot_t prot = protection_map[idx];
>> @@ -955,8 +985,180 @@ static unsigned long __init get_random_vaddr(void)
>>   	return random_vaddr;
>>   }
>>   
>> +static void __init free_mem(struct vm_pgtable_debug *debug)
>> +{
>> +	struct page *page = NULL;
>> +	int order = 0;
>> +
>> +	/* Free (huge) page */
>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>> +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
> 
> Replace #ifdef with IS_ENABLED(). There is no symbol visibility problem
> without those #ifdef here.
> 

Sure.

>> +	if (has_transparent_hugepage() &&
>> +	    debug->pud_pfn != ULONG_MAX) {
>> +		page = pfn_to_page(debug->pud_pfn);
>> +		order = HPAGE_PUD_SHIFT - PAGE_SHIFT;
>> +	}
>> +#endif
>> +
>> +	if (has_transparent_hugepage() &&
>> +	    debug->pmd_pfn != ULONG_MAX && !page) {
>> +		page = pfn_to_page(debug->pmd_pfn);
>> +		order = HPAGE_PMD_ORDER;
>> +	}
>> +#endif
>> +
>> +	if (debug->pte_pfn != ULONG_MAX && !page) {
>> +		page = pfn_to_page(debug->pte_pfn);
>> +		order = 0;
>> +	}
> 
> This could be further simplified.
> 
> 	if (debug->pud_pfn) {
> 		__free_pages(page, PUD_ORDER)
> 		done
> 	}
> 
> 	if (debug->pmd_pfn) {
> 		__free_pages(page, PMD_ORDER)
> 		done
> 	}
> 
> 	if (debug->pte_pfn)
> 		__free_pages(page, 0)
> 
> If the debug->pxx_pfn is positive and (!= ULONG_MAX), it can be assumed
> that pxx level memory was allocated successfully and is being freed up
> here. Just need to start from the highest order though.

Yes, we can bail early for each case.

> 
>> +
>> +	if (page)
>> +		__free_pages(page, order);
> 
>>From here...
> 
>> +
>> +	/* Free page table */
>> +	if (debug->start_ptep) {
>> +		pte_free(debug->mm, debug->start_ptep);
>> +		mm_dec_nr_ptes(debug->mm);
>> +	}
>> +
>> +	if (debug->start_pmdp) {
>> +		pmd_free(debug->mm, debug->start_pmdp);
>> +		mm_dec_nr_pmds(debug->mm);
>> +	}
>> +
>> +	if (debug->start_pudp) {
>> +		pud_free(debug->mm, debug->start_pudp);
>> +		mm_dec_nr_puds(debug->mm);
>> +	}
>> +
>> +	if (debug->start_p4dp)
>> +		p4d_free(debug->mm, debug->p4dp);
>> +
>> +	/* Free vma and mm struct */
>> +	if (debug->vma)
>> +		vm_area_free(debug->vma);
>> +	if (debug->mm)
>> +		mmdrop(debug->mm);
>> +}
> 
> Till here...
> 
> I am wondering whether it is really necessary to cross check all these
> elements here for being non-NULL, before freeing or rather destroying.
> Except for the allocated huge memory containing pfns and pages, all
> other elements should be asserted before proceeding with the test.
> Hence no additional checks should be required while freeing.
> 

It's possible that "struct pgtable_debug_args" isn't fully populated
by alloc_mem() when free_mem() is called. So the check is needed.
Besides, I will rename these two functions into {init, destroy}_args().

>> +
>> +static int __init alloc_mem(struct vm_pgtable_debug *debug)
>> +{
>> +	struct page *page = NULL;
>> +	phys_addr_t phys;
>> +	int ret = 0;
>> +
>> +	/* Initialize the debugging data */
>> +	debug->mm             = NULL;
>> +	debug->vma            = NULL;
>> +	debug->pgdp           = NULL;
>> +	debug->p4dp           = NULL;
>> +	debug->pudp           = NULL;
>> +	debug->pmdp           = NULL;
>> +	debug->ptep           = NULL;
>> +	debug->start_p4dp     = NULL;
>> +	debug->start_pudp     = NULL;
>> +	debug->start_pmdp     = NULL;
>> +	debug->start_ptep     = NULL;
>> +	debug->vaddr          = 0UL;
>> +	debug->page_prot      = vm_get_page_prot(VM_READ | VM_WRITE | VM_EXEC);
> 
> Should use VMFLAGS instead.
> 

Yes, VMFLAGS will be used in v2.

>> +	debug->page_prot_none = __P000;
>> +	debug->pud_pfn        = ULONG_MAX;
>> +	debug->pmd_pfn        = ULONG_MAX;
>> +	debug->pte_pfn        = ULONG_MAX;
>> +	debug->fixed_pgd_pfn  = ULONG_MAX;
>> +	debug->fixed_p4d_pfn  = ULONG_MAX;
>> +	debug->fixed_pud_pfn  = ULONG_MAX;
>> +	debug->fixed_pmd_pfn  = ULONG_MAX;
>> +	debug->fixed_pte_pfn  = ULONG_MAX;
> 
> It should instead define yet another helper, which would reset all
> structure elements to NULL or some unusable values before they get
> initialized here. Possibly [reset/clr]_debug_pgtable_args() ?
> 

I will use memset(args, 0, sizeof(*args)) in v2.

>> +
>> +	/* Allocate mm and vma */
>> +	debug->mm = mm_alloc();
>> +	if (!debug->mm) {
>> +		pr_warn("Failed to allocate mm struct\n");
>> +		ret = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	debug->vma = vm_area_alloc(debug->mm);
>> +	if (!debug->vma) {
>> +		pr_warn("Failed to allocate vma\n");
> 
> s/pr_warn/pr_err. Please dont change any warning levels here.
> 

Yes.

>> +		ret = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	/* Figure out the virtual address and allocate page table entries */
>> +	debug->vaddr = get_random_vaddr();
>> +	debug->pgdp = pgd_offset(debug->mm, debug->vaddr);
>> +	debug->p4dp = p4d_alloc(debug->mm, debug->pgdp, debug->vaddr);
>> +	debug->pudp = debug->p4dp ?
>> +		      pud_alloc(debug->mm, debug->p4dp, debug->vaddr) : NULL;
>> +	debug->pmdp = debug->pudp ?
>> +		      pmd_alloc(debug->mm, debug->pudp, debug->vaddr) : NULL;
>> +	debug->ptep = debug->pmdp ?
>> +		      pte_alloc_map(debug->mm, debug->pmdp, debug->vaddr) : NULL;
> 
> (PXXX ?) construct is really required here. Should not pxx_alloc()
> return NULL if the previous level pointer is NULL ? Regardless it
> might be better to just assert that these intermediary levels are
> allocated before proceeding further. It does not make sense to go
> ahead with the test if any of the allocations failed ! Similar to
> mm and vma.
> 

"debug->ptep" will be NULL if it fails to allocate any level of
page table. The following check for this case. We don't have to
check errors after allocating page table for every level.

> 
>> +	if (!debug->ptep) {
>> +		pr_warn("Failed to allocate page table\n");
>> +		ret = -ENOMEM;
>> +		goto error;
>> +	}
>> +
>> +	/*
>> +	 * The above page table entries will be modified. Lets save the
>> +	 * page table entries so that they can be released when the tests
>> +	 * are completed.
>> +	 */
>> +	debug->start_p4dp = p4d_offset(debug->pgdp, 0UL);
>> +	debug->start_pudp = pud_offset(debug->p4dp, 0UL);
>> +	debug->start_pmdp = pmd_offset(debug->pudp, 0UL);
>> +	debug->start_ptep = pmd_pgtable(*(debug->pmdp));
> 
> Please keep the existing construct via tmp pointer obtained from
> READ_ONCE() on (debug->pmdp) before getting used in pmd_pgtable().
> 

Yes.

>> +
>> +	/*
>> +	 * Figure out the fixed addresses, which are all around the kernel
>> +	 * symbol (@start_kernel). The corresponding PFNs might be invalid,
>> +	 * but it's fine as the following tests won't access the pages.
>> +	 */
>> +	phys = __pa_symbol(&start_kernel);
>> +	debug->fixed_pgd_pfn = __phys_to_pfn(phys & PGDIR_MASK);
>> +	debug->fixed_p4d_pfn = __phys_to_pfn(phys & P4D_MASK);
>> +	debug->fixed_pud_pfn = __phys_to_pfn(phys & PUD_MASK);
>> +	debug->fixed_pmd_pfn = __phys_to_pfn(phys & PMD_MASK);
>> +	debug->fixed_pte_pfn = __phys_to_pfn(phys & PAGE_MASK);
>> +
>> +	/*
>> +	 * Allocate (huge) pages because some of the tests need to access
>> +	 * the data in the pages. The corresponding tests will be skipped
>> +	 * if we fail to allocate (huge) pages.
>> +	 */
>> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
>> +#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
> 
> There is no symbol visibility problem without this #ifdef. Hence
> please use IS_ENABLED() constructs here instead.
> 
>> +	if (has_transparent_hugepage()) {
>> +		page = alloc_pages(GFP_KERNEL, HPAGE_PUD_SHIFT - PAGE_SHIFT);
>> +		if (page)
>> +			debug->pud_pfn = page_to_pfn(page);
> 			debug->pmd_pfn = debug->pud_pfn;
> 			debug->pte_pfn = debug->pud_pfn;
> 			done; skip;
>> +	}
>> +#endif
>> +
>> +	if (has_transparent_hugepage()) {
>> +		page = page ? page : alloc_pages(GFP_KERNEL, HPAGE_PMD_ORDER);
>> +		if (page)
>> +			debug->pmd_pfn = page_to_pfn(page);
> 			debug->pte_pfn = debug->pmd_pfn;
> 			done; skip;
>> +	}
>> +#endif
>> +
>> +	page = page ? page : alloc_pages(GFP_KERNEL, 0);
>> +	if (page)
>> +		debug->pte_pfn = page_to_pfn(page);
> 
> With the above mentioned changes (page ?) constructs should not be
> required anymore.
>

Yes, I will use IS_ENABLED(). @page might be still needed in order
to keep the code tidy.

  
>> +
>> +	return 0;
>> +
>> +error:
>> +	free_mem(debug);
>> +	return ret;
>> +}
>> +
>>   static int __init debug_vm_pgtable(void)
>>   {
>> +	struct vm_pgtable_debug debug;
> 
> This should be renamed.
> 
> s/debug/pgtable_args ?
> 

I will just have "struct pgtable_debug_args args" in v2.

>>   	struct vm_area_struct *vma;
>>   	struct mm_struct *mm;
>>   	pgd_t *pgdp;
>> @@ -970,9 +1172,13 @@ static int __init debug_vm_pgtable(void)
>>   	unsigned long vaddr, pte_aligned, pmd_aligned;
>>   	unsigned long pud_aligned, p4d_aligned, pgd_aligned;
>>   	spinlock_t *ptl = NULL;
>> -	int idx;
>> +	int idx, ret;
>>   
>>   	pr_info("Validating architecture page table helpers\n");
>> +	ret = alloc_mem(&debug);
>> +	if (ret)
>> +		return ret;
>> +
>>   	prot = vm_get_page_prot(VMFLAGS);
>>   	vaddr = get_random_vaddr();
>>   	mm = mm_alloc();
>> @@ -1127,6 +1333,8 @@ static int __init debug_vm_pgtable(void)
>>   	mm_dec_nr_pmds(mm);
>>   	mm_dec_nr_ptes(mm);
>>   	mmdrop(mm);
>> +
>> +	free_mem(&debug);
>>   	return 0;
>>   }
>>   late_initcall(debug_vm_pgtable);
>>

Thanks,
Gavin


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug
  2021-07-19  5:39     ` Gavin Shan
@ 2021-07-20  7:02       ` Anshuman Khandual
  2021-07-20 23:07         ` Gavin Shan
  0 siblings, 1 reply; 23+ messages in thread
From: Anshuman Khandual @ 2021-07-20  7:02 UTC (permalink / raw)
  To: Gavin Shan, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu



On 7/19/21 11:09 AM, Gavin Shan wrote:
> Hi Anshuman,
> 
> On 7/14/21 4:24 PM, Anshuman Khandual wrote:
>> On 7/6/21 11:47 AM, Gavin Shan wrote:
> 
> Thanks for your review. I will take all your suggestion if it's applicable.
> Otherwise, I will explain as below. All changes will be included in v2,
> which will be posted pretty soon.

You revised the series couple of times before I could even respond
here :) Anyways, I will jump to V3 directly and continue reviewing
from there.

- Anshuman

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug
  2021-07-20  7:02       ` Anshuman Khandual
@ 2021-07-20 23:07         ` Gavin Shan
  2021-07-21  4:20           ` Anshuman Khandual
  0 siblings, 1 reply; 23+ messages in thread
From: Gavin Shan @ 2021-07-20 23:07 UTC (permalink / raw)
  To: Anshuman Khandual, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu

Hi Anshuman,

On 7/20/21 5:02 PM, Anshuman Khandual wrote:
> On 7/19/21 11:09 AM, Gavin Shan wrote:
>> On 7/14/21 4:24 PM, Anshuman Khandual wrote:
>>> On 7/6/21 11:47 AM, Gavin Shan wrote:
>>
>> Thanks for your review. I will take all your suggestion if it's applicable.
>> Otherwise, I will explain as below. All changes will be included in v2,
>> which will be posted pretty soon.
> 
> You revised the series couple of times before I could even respond
> here :) Anyways, I will jump to V3 directly and continue reviewing
> from there.
> 

Yep. Sorry for the noises. Please review v3 directly. By the way,
It seems Andrew start to integrate (v3) series. I personally still
hope v3 (or perhaps v4) is going to be merged in 5.14 cycle :)

Thanks,
Gavin


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug
  2021-07-20 23:07         ` Gavin Shan
@ 2021-07-21  4:20           ` Anshuman Khandual
  0 siblings, 0 replies; 23+ messages in thread
From: Anshuman Khandual @ 2021-07-21  4:20 UTC (permalink / raw)
  To: Gavin Shan, linux-mm
  Cc: linux-kernel, catalin.marinas, will, akpm, shan.gavin, chuhu



On 7/21/21 4:37 AM, Gavin Shan wrote:
> Hi Anshuman,
> 
> On 7/20/21 5:02 PM, Anshuman Khandual wrote:
>> On 7/19/21 11:09 AM, Gavin Shan wrote:
>>> On 7/14/21 4:24 PM, Anshuman Khandual wrote:
>>>> On 7/6/21 11:47 AM, Gavin Shan wrote:
>>>
>>> Thanks for your review. I will take all your suggestion if it's applicable.
>>> Otherwise, I will explain as below. All changes will be included in v2,
>>> which will be posted pretty soon.
>>
>> You revised the series couple of times before I could even respond
>> here :) Anyways, I will jump to V3 directly and continue reviewing
>> from there.
>>
> 
> Yep. Sorry for the noises. Please review v3 directly. By the way,
> It seems Andrew start to integrate (v3) series. I personally still

That helps in getting it tested on many other platforms.

> hope v3 (or perhaps v4) is going to be merged in 5.14 cycle :)
> 
> Thanks,
> Gavin
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2021-07-21  4:20 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-06  6:17 [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Gavin Shan
2021-07-06  6:17 ` [PATCH 01/12] mm/debug_vm_pgtable: Introduce struct vm_pgtable_debug Gavin Shan
2021-07-14  6:24   ` Anshuman Khandual
2021-07-19  5:39     ` Gavin Shan
2021-07-20  7:02       ` Anshuman Khandual
2021-07-20 23:07         ` Gavin Shan
2021-07-21  4:20           ` Anshuman Khandual
2021-07-06  6:17 ` [PATCH 02/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in basic tests Gavin Shan
2021-07-06  6:17 ` [PATCH 03/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in leaf and savewrite tests Gavin Shan
2021-07-06  6:17 ` [PATCH 04/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in protnone and devmap tests Gavin Shan
2021-07-06  6:17 ` [PATCH 05/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in soft_dirty and swap tests Gavin Shan
2021-07-06  6:17 ` [PATCH 06/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in migration and thp tests Gavin Shan
2021-07-06  6:17 ` [PATCH 07/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PTE modifying tests Gavin Shan
2021-07-06  6:17 ` [PATCH 08/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PMD " Gavin Shan
2021-07-06  6:17 ` [PATCH 09/12] mm/vm_debug_pgtable: Use struct vm_pgtable_debug in PUD " Gavin Shan
2021-07-06  6:17 ` [PATCH 10/12] mm/debug_vm_pgtable: Use struct vm_pgtable_debug in PGD and P4D " Gavin Shan
2021-07-06  6:17 ` [PATCH 11/12] mm/debug_vm_pgtable: Remove unused code Gavin Shan
2021-07-06  6:17 ` [PATCH 12/12] mm/debug_vm_pgtable: Fix corrupted page flag Gavin Shan
2021-07-12  4:14 ` [PATCH 00/12] mm/debug_vm_pgtable: Enhancements Anshuman Khandual
2021-07-13  1:20   ` Gavin Shan
2021-07-14  5:26     ` Anshuman Khandual
2021-07-15  5:17       ` Gavin Shan
2021-07-18  6:36         ` Anshuman Khandual

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).