2021-07-19 05:43:48

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 00/12] mm/debug_vm_pgtable: Enhancements

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_xxx_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 pgtable_debug_args" 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 pgtable_debug_args" as place holder of all
needed information. With it, the old and new implementation
can coexist.
PATCH[2-10] uses "struct pgtable_debug_args" in various test functions.
PATCH[11] removes the old implementation.
PATCH[12] fixes the issue of corrupted page flag for ARM64

Changelog
=========
v2:
* Rename struct vm_pgtable_debug to struct pgtable_debug_args.
The parameter name to various test functions are renamed
to "@args" (Anshuman)
* Code changes as suggested by Anshuman (Anshuman)

Gavin Shan (12):
mm/debug_vm_pgtable: Introduce struct pgtable_debug_args
mm/debug_vm_pgtable: Use struct pgtable_debug_args in basic tests
mm/debug_vm_pgtable: Use struct pgtable_debug_args in leaf and
savewrite tests
mm/debug_vm_pgtable: Use struct pgtable_debug_args in protnone and
devmap tests
mm/vm_debug_pgtable: Use struct pgtable_debug_args in soft_dirty and
swap tests
mm/debug_vm_pgtable: Use struct pgtable_debug_args in migration and
thp tests
mm/debug_vm_pgtable: Use struct pgtable_debug_args in PTE modifying
tests
mm/debug_vm_pgtable: Use struct pgtable_debug_args in PMD
mm/vm_debug_pgtable: Use struct pgtable_debug_args in PUD modifying
tests
mm/debug_vm_pgtable: Use struct pgtable_debug_args 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 | 849 ++++++++++++++++++++++++------------------
1 file changed, 479 insertions(+), 370 deletions(-)

--
2.23.0


2021-07-19 05:43:51

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 06/12] mm/debug_vm_pgtable: Use struct pgtable_debug_args in migration and thp tests

This uses struct pgtable_debug_args 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 <[email protected]>
---
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 4a123bf53db8..a031f2a21c58 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -844,7 +844,7 @@ static void __init pmd_swap_tests(struct pgtable_debug_args *args)
static void __init pmd_swap_tests(struct pgtable_debug_args *args) { }
#endif /* CONFIG_ARCH_ENABLE_THP_MIGRATION */

-static void __init swap_migration_tests(void)
+static void __init swap_migration_tests(struct pgtable_debug_args *args)
{
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 = (args->pte_pfn != ULONG_MAX) ?
+ pfn_to_page(args->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 pgtable_debug_args *args) { }
#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 pgtable_debug_args *args)
{
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(args->fixed_pmd_pfn, args->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 pgtable_debug_args *args)
{
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(args->fixed_pud_pfn, args->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 pgtable_debug_args *args) { }
#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 pgtable_debug_args *args) { }
+static void __init pud_thp_tests(struct pgtable_debug_args *args) { }
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */

static unsigned long __init get_random_vaddr(void)
@@ -1270,10 +1270,10 @@ static int __init debug_vm_pgtable(void)
pte_swap_tests(&args);
pmd_swap_tests(&args);

- swap_migration_tests();
+ swap_migration_tests(&args);

- pmd_thp_tests(pmd_aligned, prot);
- pud_thp_tests(pud_aligned, prot);
+ pmd_thp_tests(&args);
+ pud_thp_tests(&args);

/*
* Page table modifying tests. They need to hold
--
2.23.0

2021-07-19 05:44:31

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 11/12] mm/debug_vm_pgtable: Remove unused code

The variables used by old implementation isn't needed as we switched
to "struct pgtable_debug_args". Lets remove it.

Signed-off-by: Gavin Shan <[email protected]>
---
mm/debug_vm_pgtable.c | 84 -------------------------------------------
1 file changed, 84 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index ca1faff6dbe3..162a12c10aa8 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -1122,17 +1122,6 @@ static int __init init_args(struct pgtable_debug_args *args)
static int __init debug_vm_pgtable(void)
{
struct pgtable_debug_args args;
- 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;

@@ -1141,68 +1130,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
@@ -1284,17 +1211,6 @@ static int __init debug_vm_pgtable(void)
pgd_populate_tests(&args);
spin_unlock(&(args.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);
-
destroy_args(&args);
return 0;
}
--
2.23.0

2021-07-19 05:44:35

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 08/12] mm/debug_vm_pgtable: Use struct pgtable_debug_args in PMD

This uses struct pgtable_debug_args 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 <[email protected]>
---
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 7be2091bd0b5..04c8d6102695 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -213,54 +213,54 @@ static void __init pmd_basic_tests(struct pgtable_debug_args *args, 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 pgtable_debug_args *args)
{
pmd_t pmd;
+ unsigned long vaddr = (args->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 (args->pmd_pfn == ULONG_MAX) {
+ pr_debug("%s: Skipped\n", __func__);
+ return;
+ }

- pgtable_trans_huge_deposit(mm, pmdp, pgtable);
+ pgtable_trans_huge_deposit(args->mm, args->pmdp, args->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(args->pmd_pfn, args->page_prot);
+ set_pmd_at(args->mm, vaddr, args->pmdp, pmd);
+ pmdp_set_wrprotect(args->mm, vaddr, args->pmdp);
+ pmd = READ_ONCE(*(args->pmdp));
WARN_ON(pmd_write(pmd));
- pmdp_huge_get_and_clear(mm, vaddr, pmdp);
- pmd = READ_ONCE(*pmdp);
+ pmdp_huge_get_and_clear(args->mm, vaddr, args->pmdp);
+ pmd = READ_ONCE(*(args->pmdp));
WARN_ON(!pmd_none(pmd));

- pmd = pfn_pmd(pfn, prot);
+ pmd = pfn_pmd(args->pmd_pfn, args->page_prot);
pmd = pmd_wrprotect(pmd);
pmd = pmd_mkclean(pmd);
- set_pmd_at(mm, vaddr, pmdp, pmd);
+ set_pmd_at(args->mm, vaddr, args->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(args->vma, vaddr, args->pmdp, pmd, 1);
+ pmd = READ_ONCE(*(args->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(args->vma, vaddr, args->pmdp, 1);
+ pmd = READ_ONCE(*(args->pmdp));
WARN_ON(!pmd_none(pmd));

- pmd = pmd_mkhuge(pfn_pmd(pfn, prot));
+ pmd = pmd_mkhuge(pfn_pmd(args->pmd_pfn, args->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(args->mm, vaddr, args->pmdp, pmd);
+ pmdp_test_and_clear_young(args->vma, vaddr, args->pmdp);
+ pmd = READ_ONCE(*(args->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(args->mm, vaddr, args->pmdp);
+ pgtable_trans_huge_withdraw(args->mm, args->pmdp);
}

static void __init pmd_leaf_tests(struct pgtable_debug_args *args)
@@ -417,12 +417,7 @@ static void __init pud_leaf_tests(struct pgtable_debug_args *args) { }
#else /* !CONFIG_TRANSPARENT_HUGEPAGE */
static void __init pmd_basic_tests(struct pgtable_debug_args *args, int idx) { }
static void __init pud_basic_tests(struct pgtable_debug_args *args, 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 pgtable_debug_args *args) { }
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 pgtable_debug_args *args) { }
#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 pgtable_debug_args *args)
{
pmd_t pmd;

- if (!arch_vmap_pmd_supported(prot))
+ if (!arch_vmap_pmd_supported(args->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(*(args->pmdp), __pmd(0));
+ WARN_ON(!pmd_set_huge(args->pmdp, __pfn_to_phys(args->fixed_pmd_pfn),
+ args->page_prot));
+ WARN_ON(!pmd_clear_huge(args->pmdp));
+ pmd = READ_ONCE(*(args->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 pgtable_debug_args *args) { }
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 pgtable_debug_args *args)
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 pgtable_debug_args *args)
{
- pmd_t pmd = READ_ONCE(*pmdp);
+ pmd_t pmd = READ_ONCE(*(args->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(*(args->pmdp), pmd);
+ pmd_clear(args->pmdp);
+ pmd = READ_ONCE(*(args->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 pgtable_debug_args *args)
{
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(args->mm, args->pmdp, args->start_ptep);
+ pmd = READ_ONCE(*(args->pmdp));
WARN_ON(pmd_bad(pmd));
}

@@ -1290,11 +1285,11 @@ static int __init debug_vm_pgtable(void)
pte_advanced_tests(&args);
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(args.mm, args.pmdp);
+ pmd_clear_tests(&args);
+ pmd_advanced_tests(&args);
+ pmd_huge_tests(&args);
+ pmd_populate_tests(&args);
spin_unlock(ptl);

ptl = pud_lock(mm, pudp);
--
2.23.0

2021-07-19 05:44:44

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 03/12] mm/debug_vm_pgtable: Use struct pgtable_debug_args in leaf and savewrite tests

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

Signed-off-by: Gavin Shan <[email protected]>
---
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 7198ea8acb79..f891b163af60 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 pgtable_debug_args *args)
{
- pte_t pte = pfn_pte(pfn, prot);
+ pte_t pte = pfn_pte(args->fixed_pte_pfn, args->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 pgtable_debug_args *args)
{
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(args->fixed_pmd_pfn, args->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 pgtable_debug_args *args)
{
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(args->fixed_pmd_pfn, args->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 pgtable_debug_args *args)
{
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(args->fixed_pud_pfn, args->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 pgtable_debug_args *args) { }
#endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
#else /* !CONFIG_TRANSPARENT_HUGEPAGE */
static void __init pmd_basic_tests(struct pgtable_debug_args *args, 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 pgtable_debug_args *args) { }
+static void __init pud_leaf_tests(struct pgtable_debug_args *args) { }
+static void __init pmd_savedwrite_tests(struct pgtable_debug_args *args) { }
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */

#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
@@ -1250,11 +1250,11 @@ static int __init debug_vm_pgtable(void)
pgd_basic_tests();
hugetlb_basic_tests(&args);

- pmd_leaf_tests(pmd_aligned, prot);
- pud_leaf_tests(pud_aligned, prot);
+ pmd_leaf_tests(&args);
+ pud_leaf_tests(&args);

- pte_savedwrite_tests(pte_aligned, protnone);
- pmd_savedwrite_tests(pmd_aligned, protnone);
+ pte_savedwrite_tests(&args);
+ pmd_savedwrite_tests(&args);

pte_special_tests(pte_aligned, prot);
pte_protnone_tests(pte_aligned, protnone);
--
2.23.0

2021-07-19 05:44:52

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 10/12] mm/debug_vm_pgtable: Use struct pgtable_debug_args in PGD and P4D modifying tests

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

Signed-off-by: Gavin Shan <[email protected]>
---
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 ebe79ad3cd29..ca1faff6dbe3 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -519,27 +519,26 @@ static void __init pud_populate_tests(struct pgtable_debug_args *args) { }
#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 pgtable_debug_args *args)
{
- p4d_t p4d = READ_ONCE(*p4dp);
+ p4d_t p4d = READ_ONCE(*(args->p4dp));

- if (mm_pud_folded(mm))
+ if (mm_pud_folded(args->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(*(args->p4dp), p4d);
+ p4d_clear(args->p4dp);
+ p4d = READ_ONCE(*(args->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 pgtable_debug_args *args)
{
p4d_t p4d;

- if (mm_pud_folded(mm))
+ if (mm_pud_folded(args->mm))
return;

pr_debug("Validating P4D populate\n");
@@ -547,34 +546,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(args->pudp);
+ p4d_clear(args->p4dp);
+ p4d_populate(args->mm, args->p4dp, args->start_pudp);
+ p4d = READ_ONCE(*(args->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 pgtable_debug_args *args)
{
- pgd_t pgd = READ_ONCE(*pgdp);
+ pgd_t pgd = READ_ONCE(*(args->pgdp));

- if (mm_p4d_folded(mm))
+ if (mm_p4d_folded(args->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(*(args->pgdp), pgd);
+ pgd_clear(args->pgdp);
+ pgd = READ_ONCE(*(args->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 pgtable_debug_args *args)
{
pgd_t pgd;

- if (mm_p4d_folded(mm))
+ if (mm_p4d_folded(args->mm))
return;

pr_debug("Validating PGD populate\n");
@@ -582,23 +580,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(args->p4dp);
+ pgd_clear(args->pgdp);
+ pgd_populate(args->mm, args->pgdp, args->start_p4dp);
+ pgd = READ_ONCE(*(args->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 pgtable_debug_args *args) { }
+static void __init pgd_clear_tests(struct pgtable_debug_args *args) { }
+static void __init p4d_populate_tests(struct pgtable_debug_args *args) { }
+static void __init pgd_populate_tests(struct pgtable_debug_args *args) { }
#endif /* PAGETABLE_P4D_FOLDED */

static void __init pte_clear_tests(struct pgtable_debug_args *args)
@@ -1285,12 +1277,12 @@ static int __init debug_vm_pgtable(void)
pud_populate_tests(&args);
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(&(args.mm->page_table_lock));
+ p4d_clear_tests(&args);
+ pgd_clear_tests(&args);
+ p4d_populate_tests(&args);
+ pgd_populate_tests(&args);
+ spin_unlock(&(args.mm->page_table_lock));

p4d_free(mm, saved_p4dp);
pud_free(mm, saved_pudp);
--
2.23.0

2021-07-19 05:45:00

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 12/12] mm/debug_vm_pgtable: Fix corrupted page flag

In page table entry modifying tests, set_xxx_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()
after set_xxx_at() is called.

Signed-off-by: Gavin Shan <[email protected]>
---
mm/debug_vm_pgtable.c | 32 ++++++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 162a12c10aa8..926d5a78f8c7 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>

@@ -118,6 +120,7 @@ static void __init pte_basic_tests(struct pgtable_debug_args *args, int idx)

static void __init pte_advanced_tests(struct pgtable_debug_args *args)
{
+ struct page *page;
pte_t pte;

/*
@@ -127,13 +130,16 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args)
*/

pr_debug("Validating PTE advanced\n");
- if (args->pte_pfn == ULONG_MAX) {
+ page = (args->pte_pfn != ULONG_MAX) ?
+ pfn_to_page(args->pte_pfn) : NULL;
+ if (!page) {
pr_debug("%s: Skipped\n", __func__);
return;
}

pte = pfn_pte(args->pte_pfn, args->page_prot);
set_pte_at(args->mm, args->vaddr, args->ptep, pte);
+ flush_dcache_page(page);
ptep_set_wrprotect(args->mm, args->vaddr, args->ptep);
pte = ptep_get(args->ptep);
WARN_ON(pte_write(pte));
@@ -145,6 +151,7 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args)
pte = pte_wrprotect(pte);
pte = pte_mkclean(pte);
set_pte_at(args->mm, args->vaddr, args->ptep, pte);
+ flush_dcache_page(page);
pte = pte_mkwrite(pte);
pte = pte_mkdirty(pte);
ptep_set_access_flags(args->vma, args->vaddr, args->ptep, pte, 1);
@@ -157,6 +164,7 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args)
pte = pfn_pte(args->pte_pfn, args->page_prot);
pte = pte_mkyoung(pte);
set_pte_at(args->mm, args->vaddr, args->ptep, pte);
+ flush_dcache_page(page);
ptep_test_and_clear_young(args->vma, args->vaddr, args->ptep);
pte = ptep_get(args->ptep);
WARN_ON(pte_young(pte));
@@ -215,6 +223,7 @@ static void __init pmd_basic_tests(struct pgtable_debug_args *args, int idx)

static void __init pmd_advanced_tests(struct pgtable_debug_args *args)
{
+ struct page *page;
pmd_t pmd;
unsigned long vaddr = (args->vaddr & HPAGE_PMD_MASK);

@@ -222,7 +231,9 @@ static void __init pmd_advanced_tests(struct pgtable_debug_args *args)
return;

pr_debug("Validating PMD advanced\n");
- if (args->pmd_pfn == ULONG_MAX) {
+ page = (args->pmd_pfn != ULONG_MAX) ?
+ pfn_to_page(args->pmd_pfn) : NULL;
+ if (!page) {
pr_debug("%s: Skipped\n", __func__);
return;
}
@@ -231,6 +242,7 @@ static void __init pmd_advanced_tests(struct pgtable_debug_args *args)

pmd = pfn_pmd(args->pmd_pfn, args->page_prot);
set_pmd_at(args->mm, vaddr, args->pmdp, pmd);
+ flush_dcache_page(page);
pmdp_set_wrprotect(args->mm, vaddr, args->pmdp);
pmd = READ_ONCE(*(args->pmdp));
WARN_ON(pmd_write(pmd));
@@ -242,6 +254,7 @@ static void __init pmd_advanced_tests(struct pgtable_debug_args *args)
pmd = pmd_wrprotect(pmd);
pmd = pmd_mkclean(pmd);
set_pmd_at(args->mm, vaddr, args->pmdp, pmd);
+ flush_dcache_page(page);
pmd = pmd_mkwrite(pmd);
pmd = pmd_mkdirty(pmd);
pmdp_set_access_flags(args->vma, vaddr, args->pmdp, pmd, 1);
@@ -254,6 +267,7 @@ static void __init pmd_advanced_tests(struct pgtable_debug_args *args)
pmd = pmd_mkhuge(pfn_pmd(args->pmd_pfn, args->page_prot));
pmd = pmd_mkyoung(pmd);
set_pmd_at(args->mm, vaddr, args->pmdp, pmd);
+ flush_dcache_page(page);
pmdp_test_and_clear_young(args->vma, vaddr, args->pmdp);
pmd = READ_ONCE(*(args->pmdp));
WARN_ON(pmd_young(pmd));
@@ -340,6 +354,7 @@ static void __init pud_basic_tests(struct pgtable_debug_args *args, int idx)

static void __init pud_advanced_tests(struct pgtable_debug_args *args)
{
+ struct page *page;
unsigned long vaddr = (args->vaddr & HPAGE_PUD_MASK);
pud_t pud;

@@ -347,13 +362,16 @@ static void __init pud_advanced_tests(struct pgtable_debug_args *args)
return;

pr_debug("Validating PUD advanced\n");
- if (args->pud_pfn == ULONG_MAX) {
+ page = (args->pud_pfn != ULONG_MAX) ?
+ pfn_to_page(args->pud_pfn) : NULL;
+ if (!page) {
pr_debug("%s: Skipped\n", __func__);
return;
}

pud = pfn_pud(args->pud_pfn, args->page_prot);
set_pud_at(args->mm, vaddr, args->pudp, pud);
+ flush_dcache_page(page);
pudp_set_wrprotect(args->mm, vaddr, args->pudp);
pud = READ_ONCE(*(args->pudp));
WARN_ON(pud_write(pud));
@@ -367,6 +385,7 @@ static void __init pud_advanced_tests(struct pgtable_debug_args *args)
pud = pud_wrprotect(pud);
pud = pud_mkclean(pud);
set_pud_at(args->mm, vaddr, args->pudp, pud);
+ flush_dcache_page(page);
pud = pud_mkwrite(pud);
pud = pud_mkdirty(pud);
pudp_set_access_flags(args->vma, vaddr, args->pudp, pud, 1);
@@ -382,6 +401,7 @@ static void __init pud_advanced_tests(struct pgtable_debug_args *args)
pud = pfn_pud(args->pud_pfn, args->page_prot);
pud = pud_mkyoung(pud);
set_pud_at(args->mm, vaddr, args->pudp, pud);
+ flush_dcache_page(page);
pudp_test_and_clear_young(args->vma, vaddr, args->pudp);
pud = READ_ONCE(*(args->pudp));
WARN_ON(pud_young(pud));
@@ -595,10 +615,13 @@ static void __init pgd_populate_tests(struct pgtable_debug_args *args) { }

static void __init pte_clear_tests(struct pgtable_debug_args *args)
{
+ struct page *page;
pte_t pte;

pr_debug("Validating PTE clear\n");
- if (args->pte_pfn == ULONG_MAX) {
+ page = (args->pte_pfn != ULONG_MAX) ?
+ pfn_to_page(args->pte_pfn) : NULL;
+ if (!page) {
pr_debug("%s: Skipped\n", __func__);
return;
}
@@ -608,6 +631,7 @@ static void __init pte_clear_tests(struct pgtable_debug_args *args)
pte = __pte(pte_val(pte) | RANDOM_ORVALUE);
#endif
set_pte_at(args->mm, args->vaddr, args->ptep, pte);
+ flush_dcache_page(page);
barrier();
pte_clear(args->mm, args->vaddr, args->ptep);
pte = ptep_get(args->ptep);
--
2.23.0

2021-07-19 05:46:04

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 07/12] mm/debug_vm_pgtable: Use struct pgtable_debug_args in PTE modifying tests

This uses struct pgtable_debug_args 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 <[email protected]>
---
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 a031f2a21c58..7be2091bd0b5 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -116,10 +116,7 @@ static void __init pte_basic_tests(struct pgtable_debug_args *args, 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 pgtable_debug_args *args)
{
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 (args->pte_pfn == ULONG_MAX) {
+ pr_debug("%s: Skipped\n", __func__);
+ return;
+ }
+
+ pte = pfn_pte(args->pte_pfn, args->page_prot);
+ set_pte_at(args->mm, args->vaddr, args->ptep, pte);
+ ptep_set_wrprotect(args->mm, args->vaddr, args->ptep);
+ pte = ptep_get(args->ptep);
WARN_ON(pte_write(pte));
- ptep_get_and_clear(mm, vaddr, ptep);
- pte = ptep_get(ptep);
+ ptep_get_and_clear(args->mm, args->vaddr, args->ptep);
+ pte = ptep_get(args->ptep);
WARN_ON(!pte_none(pte));

- pte = pfn_pte(pfn, prot);
+ pte = pfn_pte(args->pte_pfn, args->page_prot);
pte = pte_wrprotect(pte);
pte = pte_mkclean(pte);
- set_pte_at(mm, vaddr, ptep, pte);
+ set_pte_at(args->mm, args->vaddr, args->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(args->vma, args->vaddr, args->ptep, pte, 1);
+ pte = ptep_get(args->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(args->mm, args->vaddr, args->ptep, 1);
+ pte = ptep_get(args->ptep);
WARN_ON(!pte_none(pte));

- pte = pfn_pte(pfn, prot);
+ pte = pfn_pte(args->pte_pfn, args->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(args->mm, args->vaddr, args->ptep, pte);
+ ptep_test_and_clear_young(args->vma, args->vaddr, args->ptep);
+ pte = ptep_get(args->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 pgtable_debug_args *args)
{
- pte_t pte = pfn_pte(pfn, prot);
+ pte_t pte;

pr_debug("Validating PTE clear\n");
+ if (args->pte_pfn == ULONG_MAX) {
+ pr_debug("%s: Skipped\n", __func__);
+ return;
+ }
+
+ pte = pfn_pte(args->pte_pfn, args->page_prot);
#ifndef CONFIG_RISCV
pte = __pte(pte_val(pte) | RANDOM_ORVALUE);
#endif
- set_pte_at(mm, vaddr, ptep, pte);
+ set_pte_at(args->mm, args->vaddr, args->ptep, pte);
barrier();
- pte_clear(mm, vaddr, ptep);
- pte = ptep_get(ptep);
+ pte_clear(args->mm, args->vaddr, args->ptep);
+ pte = ptep_get(args->ptep);
WARN_ON(!pte_none(pte));
}

@@ -1149,7 +1155,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;
@@ -1279,11 +1284,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(args.mm, args.pmdp);
+ spin_lock(ptl);
+ pte_clear_tests(&args);
+ pte_advanced_tests(&args);
+ spin_unlock(ptl);

ptl = pmd_lock(mm, pmdp);
pmd_clear_tests(mm, pmdp);
--
2.23.0

2021-07-19 05:46:18

by Gavin Shan

[permalink] [raw]
Subject: [PATCH v2 09/12] mm/vm_debug_pgtable: Use struct pgtable_debug_args in PUD modifying tests

This uses struct pgtable_debug_args 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 <[email protected]>
---
mm/debug_vm_pgtable.c | 114 ++++++++++++++++++------------------------
1 file changed, 50 insertions(+), 64 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 04c8d6102695..ebe79ad3cd29 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -338,55 +338,55 @@ static void __init pud_basic_tests(struct pgtable_debug_args *args, 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 pgtable_debug_args *args)
{
+ unsigned long vaddr = (args->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 (args->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(args->pud_pfn, args->page_prot);
+ set_pud_at(args->mm, vaddr, args->pudp, pud);
+ pudp_set_wrprotect(args->mm, vaddr, args->pudp);
+ pud = READ_ONCE(*(args->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(args->mm, vaddr, args->pudp);
+ pud = READ_ONCE(*(args->pudp));
WARN_ON(!pud_none(pud));
#endif /* __PAGETABLE_PMD_FOLDED */
- pud = pfn_pud(pfn, prot);
+ pud = pfn_pud(args->pud_pfn, args->page_prot);
pud = pud_wrprotect(pud);
pud = pud_mkclean(pud);
- set_pud_at(mm, vaddr, pudp, pud);
+ set_pud_at(args->mm, vaddr, args->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(args->vma, vaddr, args->pudp, pud, 1);
+ pud = READ_ONCE(*(args->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(args->mm, vaddr, args->pudp, 1);
+ pud = READ_ONCE(*(args->pudp));
WARN_ON(!pud_none(pud));
#endif /* __PAGETABLE_PMD_FOLDED */

- pud = pfn_pud(pfn, prot);
+ pud = pfn_pud(args->pud_pfn, args->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(args->mm, vaddr, args->pudp, pud);
+ pudp_test_and_clear_young(args->vma, vaddr, args->pudp);
+ pud = READ_ONCE(*(args->pudp));
WARN_ON(pud_young(pud));

- pudp_huge_get_and_clear(mm, vaddr, pudp);
+ pudp_huge_get_and_clear(args->mm, vaddr, args->pudp);
}

static void __init pud_leaf_tests(struct pgtable_debug_args *args)
@@ -406,24 +406,14 @@ static void __init pud_leaf_tests(struct pgtable_debug_args *args)
}
#else /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
static void __init pud_basic_tests(struct pgtable_debug_args *args, 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 pgtable_debug_args *args) { }
static void __init pud_leaf_tests(struct pgtable_debug_args *args) { }
#endif /* CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
#else /* !CONFIG_TRANSPARENT_HUGEPAGE */
static void __init pmd_basic_tests(struct pgtable_debug_args *args, int idx) { }
static void __init pud_basic_tests(struct pgtable_debug_args *args, int idx) { }
static void __init pmd_advanced_tests(struct pgtable_debug_args *args) { }
-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 pgtable_debug_args *args) { }
static void __init pmd_leaf_tests(struct pgtable_debug_args *args) { }
static void __init pud_leaf_tests(struct pgtable_debug_args *args) { }
static void __init pmd_savedwrite_tests(struct pgtable_debug_args *args) { }
@@ -450,11 +440,11 @@ static void __init pmd_huge_tests(struct pgtable_debug_args *args)
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 pgtable_debug_args *args)
{
pud_t pud;

- if (!arch_vmap_pud_supported(prot))
+ if (!arch_vmap_pud_supported(args->page_prot))
return;

pr_debug("Validating PUD huge\n");
@@ -462,15 +452,15 @@ 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);
- WARN_ON(!pud_none(pud));
+ WRITE_ONCE(*(args->pudp), __pud(0));
+ WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn),
+ args->page_prot));
+ WARN_ON(!pud_clear_huge(args->pudp));
+ pud = READ_ONCE(*(args->pudp));
}
#else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
static void __init pmd_huge_tests(struct pgtable_debug_args *args) { }
-static void __init pud_huge_tests(pud_t *pudp, unsigned long pfn, pgprot_t prot) { }
+static void __init pud_huge_tests(struct pgtable_debug_args *args) { }
#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */

static void __init p4d_basic_tests(void)
@@ -492,27 +482,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 pgtable_debug_args *args)
{
- pud_t pud = READ_ONCE(*pudp);
+ pud_t pud = READ_ONCE(*(args->pudp));

- if (mm_pmd_folded(mm))
+ if (mm_pmd_folded(args->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(*(args->pudp), pud);
+ pud_clear(args->pudp);
+ pud = READ_ONCE(*(args->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 pgtable_debug_args *args)
{
pud_t pud;

- if (mm_pmd_folded(mm))
+ if (mm_pmd_folded(args->mm))
return;

pr_debug("Validating PUD populate\n");
@@ -520,16 +509,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(args->mm, args->pudp, args->start_pmdp);
+ pud = READ_ONCE(*(args->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 pgtable_debug_args *args) { }
+static void __init pud_populate_tests(struct pgtable_debug_args *args) { }
#endif /* PAGETABLE_PUD_FOLDED */

#ifndef __PAGETABLE_P4D_FOLDED
@@ -1292,11 +1278,11 @@ static int __init debug_vm_pgtable(void)
pmd_populate_tests(&args);
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(args.mm, args.pudp);
+ pud_clear_tests(&args);
+ pud_advanced_tests(&args);
+ pud_huge_tests(&args);
+ pud_populate_tests(&args);
spin_unlock(ptl);

spin_lock(&mm->page_table_lock);
--
2.23.0

2021-07-19 09:14:55

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 09/12] mm/vm_debug_pgtable: Use struct pgtable_debug_args in PUD modifying tests

Hi Gavin,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.14-rc2]
[cannot apply to hnaz-linux-mm/master linux/master next-20210716]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2734d6c1b1a089fb593ef6a23d4b70903526fe0c
config: arm64-randconfig-r005-20210719 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 5d5b08761f944d5b9822d582378333cc4b36a0a7)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm64 cross compiling tool for clang build
# apt-get install binutils-aarch64-linux-gnu
# https://github.com/0day-ci/linux/commit/69db26024e6bd48423ebc83b0f83b7b52217b624
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
git checkout 69db26024e6bd48423ebc83b0f83b7b52217b624
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=arm64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> mm/debug_vm_pgtable.c:445:8: warning: variable 'pud' set but not used [-Wunused-but-set-variable]
pud_t pud;
^
mm/debug_vm_pgtable.c:1140:17: warning: variable 'protnone' set but not used [-Wunused-but-set-variable]
pgprot_t prot, protnone;
^
mm/debug_vm_pgtable.c:1142:36: warning: variable 'pmd_aligned' set but not used [-Wunused-but-set-variable]
unsigned long vaddr, pte_aligned, pmd_aligned;
^
mm/debug_vm_pgtable.c:1143:42: warning: variable 'pgd_aligned' set but not used [-Wunused-but-set-variable]
unsigned long pud_aligned, p4d_aligned, pgd_aligned;
^
mm/debug_vm_pgtable.c:1143:29: warning: variable 'p4d_aligned' set but not used [-Wunused-but-set-variable]
unsigned long pud_aligned, p4d_aligned, pgd_aligned;
^
mm/debug_vm_pgtable.c:1143:16: warning: variable 'pud_aligned' set but not used [-Wunused-but-set-variable]
unsigned long pud_aligned, p4d_aligned, pgd_aligned;
^
mm/debug_vm_pgtable.c:1140:11: warning: variable 'prot' set but not used [-Wunused-but-set-variable]
pgprot_t prot, protnone;
^
7 warnings generated.


vim +/pud +445 mm/debug_vm_pgtable.c

5fe77be6bf14bf Shixin Liu 2021-06-30 442
69db26024e6bd4 Gavin Shan 2021-07-19 443 static void __init pud_huge_tests(struct pgtable_debug_args *args)
a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 444 {
5fe77be6bf14bf Shixin Liu 2021-06-30 @445 pud_t pud;
5fe77be6bf14bf Shixin Liu 2021-06-30 446
69db26024e6bd4 Gavin Shan 2021-07-19 447 if (!arch_vmap_pud_supported(args->page_prot))
5fe77be6bf14bf Shixin Liu 2021-06-30 448 return;
5fe77be6bf14bf Shixin Liu 2021-06-30 449
5fe77be6bf14bf Shixin Liu 2021-06-30 450 pr_debug("Validating PUD huge\n");
5fe77be6bf14bf Shixin Liu 2021-06-30 451 /*
5fe77be6bf14bf Shixin Liu 2021-06-30 452 * X86 defined pud_set_huge() verifies that the given
5fe77be6bf14bf Shixin Liu 2021-06-30 453 * PUD is not a populated non-leaf entry.
5fe77be6bf14bf Shixin Liu 2021-06-30 454 */
69db26024e6bd4 Gavin Shan 2021-07-19 455 WRITE_ONCE(*(args->pudp), __pud(0));
69db26024e6bd4 Gavin Shan 2021-07-19 456 WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn),
69db26024e6bd4 Gavin Shan 2021-07-19 457 args->page_prot));
69db26024e6bd4 Gavin Shan 2021-07-19 458 WARN_ON(!pud_clear_huge(args->pudp));
69db26024e6bd4 Gavin Shan 2021-07-19 459 pud = READ_ONCE(*(args->pudp));
a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 460 }
5fe77be6bf14bf Shixin Liu 2021-06-30 461 #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
54b1f4b50ddb0f Gavin Shan 2021-07-19 462 static void __init pmd_huge_tests(struct pgtable_debug_args *args) { }
69db26024e6bd4 Gavin Shan 2021-07-19 463 static void __init pud_huge_tests(struct pgtable_debug_args *args) { }
5fe77be6bf14bf Shixin Liu 2021-06-30 464 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
399145f9eb6c67 Anshuman Khandual 2020-06-04 465

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (5.09 kB)
.config.gz (43.88 kB)
Download all attachments

2021-07-19 11:33:34

by Gavin Shan

[permalink] [raw]
Subject: Re: [PATCH v2 09/12] mm/vm_debug_pgtable: Use struct pgtable_debug_args in PUD modifying tests

On 7/19/21 7:13 PM, kernel test robot wrote:
> Hi Gavin,
>
> Thank you for the patch! Perhaps something to improve:
>
> [auto build test WARNING on linus/master]
> [also build test WARNING on v5.14-rc2]
> [cannot apply to hnaz-linux-mm/master linux/master next-20210716]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
>
> url: https://github.com/0day-ci/linux/commits/Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
> base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2734d6c1b1a089fb593ef6a23d4b70903526fe0c
> config: arm64-randconfig-r005-20210719 (attached as .config)
> compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 5d5b08761f944d5b9822d582378333cc4b36a0a7)
> reproduce (this is a W=1 build):
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # install arm64 cross compiling tool for clang build
> # apt-get install binutils-aarch64-linux-gnu
> # https://github.com/0day-ci/linux/commit/69db26024e6bd48423ebc83b0f83b7b52217b624
> git remote add linux-review https://github.com/0day-ci/linux
> git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
> git checkout 69db26024e6bd48423ebc83b0f83b7b52217b624
> # save the attached .config to linux build tree
> COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=arm64
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <[email protected]>
>

Thanks for reporting the build warnings. I will fix it in v3.

> All warnings (new ones prefixed by >>):
>
>>> mm/debug_vm_pgtable.c:445:8: warning: variable 'pud' set but not used [-Wunused-but-set-variable]
> pud_t pud;
>

A "WARN_ON(!pud_none(pud)) is missed from PATCH[9/12].

^
> mm/debug_vm_pgtable.c:1140:17: warning: variable 'protnone' set but not used [-Wunused-but-set-variable]
> pgprot_t prot, protnone;
> ^
> mm/debug_vm_pgtable.c:1142:36: warning: variable 'pmd_aligned' set but not used [-Wunused-but-set-variable]
> unsigned long vaddr, pte_aligned, pmd_aligned;
> ^
> mm/debug_vm_pgtable.c:1143:42: warning: variable 'pgd_aligned' set but not used [-Wunused-but-set-variable]
> unsigned long pud_aligned, p4d_aligned, pgd_aligned;
> ^
> mm/debug_vm_pgtable.c:1143:29: warning: variable 'p4d_aligned' set but not used [-Wunused-but-set-variable]
> unsigned long pud_aligned, p4d_aligned, pgd_aligned;
> ^
> mm/debug_vm_pgtable.c:1143:16: warning: variable 'pud_aligned' set but not used [-Wunused-but-set-variable]
> unsigned long pud_aligned, p4d_aligned, pgd_aligned;
> ^
> mm/debug_vm_pgtable.c:1140:11: warning: variable 'prot' set but not used [-Wunused-but-set-variable]
> pgprot_t prot, protnone;
> ^
> 7 warnings generated.
>

There are more build warnings introduced by other patches. I need to drop the unused
variables in debug_vm_pgtable(). So I need to drop the unused variables in separate
patches in v3, instead of dropping all of them in PATCH[v2 11/12].

Thanks,
Gavin

>
> vim +/pud +445 mm/debug_vm_pgtable.c
>
> 5fe77be6bf14bf Shixin Liu 2021-06-30 442
> 69db26024e6bd4 Gavin Shan 2021-07-19 443 static void __init pud_huge_tests(struct pgtable_debug_args *args)
> a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 444 {
> 5fe77be6bf14bf Shixin Liu 2021-06-30 @445 pud_t pud;
> 5fe77be6bf14bf Shixin Liu 2021-06-30 446
> 69db26024e6bd4 Gavin Shan 2021-07-19 447 if (!arch_vmap_pud_supported(args->page_prot))
> 5fe77be6bf14bf Shixin Liu 2021-06-30 448 return;
> 5fe77be6bf14bf Shixin Liu 2021-06-30 449
> 5fe77be6bf14bf Shixin Liu 2021-06-30 450 pr_debug("Validating PUD huge\n");
> 5fe77be6bf14bf Shixin Liu 2021-06-30 451 /*
> 5fe77be6bf14bf Shixin Liu 2021-06-30 452 * X86 defined pud_set_huge() verifies that the given
> 5fe77be6bf14bf Shixin Liu 2021-06-30 453 * PUD is not a populated non-leaf entry.
> 5fe77be6bf14bf Shixin Liu 2021-06-30 454 */
> 69db26024e6bd4 Gavin Shan 2021-07-19 455 WRITE_ONCE(*(args->pudp), __pud(0));
> 69db26024e6bd4 Gavin Shan 2021-07-19 456 WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn),
> 69db26024e6bd4 Gavin Shan 2021-07-19 457 args->page_prot));
> 69db26024e6bd4 Gavin Shan 2021-07-19 458 WARN_ON(!pud_clear_huge(args->pudp));
> 69db26024e6bd4 Gavin Shan 2021-07-19 459 pud = READ_ONCE(*(args->pudp));
> a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 460 }
> 5fe77be6bf14bf Shixin Liu 2021-06-30 461 #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
> 54b1f4b50ddb0f Gavin Shan 2021-07-19 462 static void __init pmd_huge_tests(struct pgtable_debug_args *args) { }
> 69db26024e6bd4 Gavin Shan 2021-07-19 463 static void __init pud_huge_tests(struct pgtable_debug_args *args) { }
> 5fe77be6bf14bf Shixin Liu 2021-06-30 464 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
> 399145f9eb6c67 Anshuman Khandual 2020-06-04 465
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/[email protected]
>

2021-07-19 11:34:38

by Gavin Shan

[permalink] [raw]
Subject: Re: [PATCH v2 00/12] mm/debug_vm_pgtable: Enhancements

Hi Anshuman,

On 7/19/21 3:41 PM, 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.
>
> (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_xxx_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 pgtable_debug_args" 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 pgtable_debug_args" as place holder of all
> needed information. With it, the old and new implementation
> can coexist.
> PATCH[2-10] uses "struct pgtable_debug_args" in various test functions.
> PATCH[11] removes the old implementation.
> PATCH[12] fixes the issue of corrupted page flag for ARM64
>
> Changelog
> =========
> v2:
> * Rename struct vm_pgtable_debug to struct pgtable_debug_args.
> The parameter name to various test functions are renamed
> to "@args" (Anshuman)
> * Code changes as suggested by Anshuman (Anshuman)
>

Please ignore v2. I will post v3 to fix couple of issues in v2:

(1) The subjects of PATCH[5/12] and PATCH[9/12] should be fixed to
start with "mm/debug_vm_pgtable".
(2) "WARN_ON(!pud_none(pud))" is missed in PATCH[9/12]. Otherwise,
build warning for unused variable @pud is raised.
(3) Build warnings for unused variables in separate patches are
raised, reported by 0-DAY CI Kernel Test Service.

Thanks,
Gavin

> Gavin Shan (12):
> mm/debug_vm_pgtable: Introduce struct pgtable_debug_args
> mm/debug_vm_pgtable: Use struct pgtable_debug_args in basic tests
> mm/debug_vm_pgtable: Use struct pgtable_debug_args in leaf and
> savewrite tests
> mm/debug_vm_pgtable: Use struct pgtable_debug_args in protnone and
> devmap tests
> mm/vm_debug_pgtable: Use struct pgtable_debug_args in soft_dirty and
> swap tests
> mm/debug_vm_pgtable: Use struct pgtable_debug_args in migration and
> thp tests
> mm/debug_vm_pgtable: Use struct pgtable_debug_args in PTE modifying
> tests
> mm/debug_vm_pgtable: Use struct pgtable_debug_args in PMD
> mm/vm_debug_pgtable: Use struct pgtable_debug_args in PUD modifying
> tests
> mm/debug_vm_pgtable: Use struct pgtable_debug_args 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 | 849 ++++++++++++++++++++++++------------------
> 1 file changed, 479 insertions(+), 370 deletions(-)
>

2021-07-20 06:18:05

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 09/12] mm/vm_debug_pgtable: Use struct pgtable_debug_args in PUD modifying tests

Hi Gavin,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.14-rc2]
[cannot apply to hnaz-linux-mm/master linux/master next-20210719]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2734d6c1b1a089fb593ef6a23d4b70903526fe0c
config: x86_64-randconfig-c002-20210719 (attached as .config)
compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0
reproduce (this is a W=1 build):
# https://github.com/0day-ci/linux/commit/69db26024e6bd48423ebc83b0f83b7b52217b624
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
git checkout 69db26024e6bd48423ebc83b0f83b7b52217b624
# save the attached .config to linux build tree
make W=1 ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

mm/debug_vm_pgtable.c: In function 'pud_huge_tests':
>> mm/debug_vm_pgtable.c:445:8: warning: variable 'pud' set but not used [-Wunused-but-set-variable]
445 | pud_t pud;
| ^~~
mm/debug_vm_pgtable.c: In function 'debug_vm_pgtable':
mm/debug_vm_pgtable.c:1143:42: warning: variable 'pgd_aligned' set but not used [-Wunused-but-set-variable]
1143 | unsigned long pud_aligned, p4d_aligned, pgd_aligned;
| ^~~~~~~~~~~
mm/debug_vm_pgtable.c:1143:29: warning: variable 'p4d_aligned' set but not used [-Wunused-but-set-variable]
1143 | unsigned long pud_aligned, p4d_aligned, pgd_aligned;
| ^~~~~~~~~~~
mm/debug_vm_pgtable.c:1143:16: warning: variable 'pud_aligned' set but not used [-Wunused-but-set-variable]
1143 | unsigned long pud_aligned, p4d_aligned, pgd_aligned;
| ^~~~~~~~~~~
mm/debug_vm_pgtable.c:1142:36: warning: variable 'pmd_aligned' set but not used [-Wunused-but-set-variable]
1142 | unsigned long vaddr, pte_aligned, pmd_aligned;
| ^~~~~~~~~~~
mm/debug_vm_pgtable.c:1140:17: warning: variable 'protnone' set but not used [-Wunused-but-set-variable]
1140 | pgprot_t prot, protnone;
| ^~~~~~~~
mm/debug_vm_pgtable.c:1140:11: warning: variable 'prot' set but not used [-Wunused-but-set-variable]
1140 | pgprot_t prot, protnone;
| ^~~~


vim +/pud +445 mm/debug_vm_pgtable.c

5fe77be6bf14bf Shixin Liu 2021-06-30 442
69db26024e6bd4 Gavin Shan 2021-07-19 443 static void __init pud_huge_tests(struct pgtable_debug_args *args)
a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 444 {
5fe77be6bf14bf Shixin Liu 2021-06-30 @445 pud_t pud;
5fe77be6bf14bf Shixin Liu 2021-06-30 446
69db26024e6bd4 Gavin Shan 2021-07-19 447 if (!arch_vmap_pud_supported(args->page_prot))
5fe77be6bf14bf Shixin Liu 2021-06-30 448 return;
5fe77be6bf14bf Shixin Liu 2021-06-30 449
5fe77be6bf14bf Shixin Liu 2021-06-30 450 pr_debug("Validating PUD huge\n");
5fe77be6bf14bf Shixin Liu 2021-06-30 451 /*
5fe77be6bf14bf Shixin Liu 2021-06-30 452 * X86 defined pud_set_huge() verifies that the given
5fe77be6bf14bf Shixin Liu 2021-06-30 453 * PUD is not a populated non-leaf entry.
5fe77be6bf14bf Shixin Liu 2021-06-30 454 */
69db26024e6bd4 Gavin Shan 2021-07-19 455 WRITE_ONCE(*(args->pudp), __pud(0));
69db26024e6bd4 Gavin Shan 2021-07-19 456 WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn),
69db26024e6bd4 Gavin Shan 2021-07-19 457 args->page_prot));
69db26024e6bd4 Gavin Shan 2021-07-19 458 WARN_ON(!pud_clear_huge(args->pudp));
69db26024e6bd4 Gavin Shan 2021-07-19 459 pud = READ_ONCE(*(args->pudp));
a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 460 }
5fe77be6bf14bf Shixin Liu 2021-06-30 461 #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
54b1f4b50ddb0f Gavin Shan 2021-07-19 462 static void __init pmd_huge_tests(struct pgtable_debug_args *args) { }
69db26024e6bd4 Gavin Shan 2021-07-19 463 static void __init pud_huge_tests(struct pgtable_debug_args *args) { }
5fe77be6bf14bf Shixin Liu 2021-06-30 464 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
399145f9eb6c67 Anshuman Khandual 2020-06-04 465

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (4.89 kB)
.config.gz (41.56 kB)
Download all attachments

2021-07-20 23:10:26

by Gavin Shan

[permalink] [raw]
Subject: Re: [PATCH v2 09/12] mm/vm_debug_pgtable: Use struct pgtable_debug_args in PUD modifying tests

On 7/20/21 12:46 PM, kernel test robot wrote:
> Hi Gavin,
>
> Thank you for the patch! Perhaps something to improve:
>
> [auto build test WARNING on linus/master]
> [also build test WARNING on v5.14-rc2]
> [cannot apply to hnaz-linux-mm/master linux/master next-20210719]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
>
> url: https://github.com/0day-ci/linux/commits/Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
> base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2734d6c1b1a089fb593ef6a23d4b70903526fe0c
> config: x86_64-randconfig-c002-20210719 (attached as .config)
> compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0
> reproduce (this is a W=1 build):
> # https://github.com/0day-ci/linux/commit/69db26024e6bd48423ebc83b0f83b7b52217b624
> git remote add linux-review https://github.com/0day-ci/linux
> git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Enhancements/20210719-134236
> git checkout 69db26024e6bd48423ebc83b0f83b7b52217b624
> # save the attached .config to linux build tree
> make W=1 ARCH=x86_64
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <[email protected]>
>
> All warnings (new ones prefixed by >>):
>
> mm/debug_vm_pgtable.c: In function 'pud_huge_tests':
>>> mm/debug_vm_pgtable.c:445:8: warning: variable 'pud' set but not used [-Wunused-but-set-variable]
> 445 | pud_t pud;
> | ^~~
> mm/debug_vm_pgtable.c: In function 'debug_vm_pgtable':
> mm/debug_vm_pgtable.c:1143:42: warning: variable 'pgd_aligned' set but not used [-Wunused-but-set-variable]
> 1143 | unsigned long pud_aligned, p4d_aligned, pgd_aligned;
> | ^~~~~~~~~~~
> mm/debug_vm_pgtable.c:1143:29: warning: variable 'p4d_aligned' set but not used [-Wunused-but-set-variable]
> 1143 | unsigned long pud_aligned, p4d_aligned, pgd_aligned;
> | ^~~~~~~~~~~
> mm/debug_vm_pgtable.c:1143:16: warning: variable 'pud_aligned' set but not used [-Wunused-but-set-variable]
> 1143 | unsigned long pud_aligned, p4d_aligned, pgd_aligned;
> | ^~~~~~~~~~~
> mm/debug_vm_pgtable.c:1142:36: warning: variable 'pmd_aligned' set but not used [-Wunused-but-set-variable]
> 1142 | unsigned long vaddr, pte_aligned, pmd_aligned;
> | ^~~~~~~~~~~
> mm/debug_vm_pgtable.c:1140:17: warning: variable 'protnone' set but not used [-Wunused-but-set-variable]
> 1140 | pgprot_t prot, protnone;
> | ^~~~~~~~
> mm/debug_vm_pgtable.c:1140:11: warning: variable 'prot' set but not used [-Wunused-but-set-variable]
> 1140 | pgprot_t prot, protnone;
> | ^~~~
>

Please ignore these build warnings raised against v2 series because all of them
should have been fixed in v3 series.

Thanks,
Gavin

>
> vim +/pud +445 mm/debug_vm_pgtable.c
>
> 5fe77be6bf14bf Shixin Liu 2021-06-30 442
> 69db26024e6bd4 Gavin Shan 2021-07-19 443 static void __init pud_huge_tests(struct pgtable_debug_args *args)
> a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 444 {
> 5fe77be6bf14bf Shixin Liu 2021-06-30 @445 pud_t pud;
> 5fe77be6bf14bf Shixin Liu 2021-06-30 446
> 69db26024e6bd4 Gavin Shan 2021-07-19 447 if (!arch_vmap_pud_supported(args->page_prot))
> 5fe77be6bf14bf Shixin Liu 2021-06-30 448 return;
> 5fe77be6bf14bf Shixin Liu 2021-06-30 449
> 5fe77be6bf14bf Shixin Liu 2021-06-30 450 pr_debug("Validating PUD huge\n");
> 5fe77be6bf14bf Shixin Liu 2021-06-30 451 /*
> 5fe77be6bf14bf Shixin Liu 2021-06-30 452 * X86 defined pud_set_huge() verifies that the given
> 5fe77be6bf14bf Shixin Liu 2021-06-30 453 * PUD is not a populated non-leaf entry.
> 5fe77be6bf14bf Shixin Liu 2021-06-30 454 */
> 69db26024e6bd4 Gavin Shan 2021-07-19 455 WRITE_ONCE(*(args->pudp), __pud(0));
> 69db26024e6bd4 Gavin Shan 2021-07-19 456 WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn),
> 69db26024e6bd4 Gavin Shan 2021-07-19 457 args->page_prot));
> 69db26024e6bd4 Gavin Shan 2021-07-19 458 WARN_ON(!pud_clear_huge(args->pudp));
> 69db26024e6bd4 Gavin Shan 2021-07-19 459 pud = READ_ONCE(*(args->pudp));
> a5c3b9ffb0f404 Anshuman Khandual 2020-08-06 460 }
> 5fe77be6bf14bf Shixin Liu 2021-06-30 461 #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
> 54b1f4b50ddb0f Gavin Shan 2021-07-19 462 static void __init pmd_huge_tests(struct pgtable_debug_args *args) { }
> 69db26024e6bd4 Gavin Shan 2021-07-19 463 static void __init pud_huge_tests(struct pgtable_debug_args *args) { }
> 5fe77be6bf14bf Shixin Liu 2021-06-30 464 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
> 399145f9eb6c67 Anshuman Khandual 2020-06-04 465
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/[email protected]
>