diff mbox series

mm/debug_vm_pgtable: Fix corrupted PG_arch_1 by set_pmd_at()

Message ID 20210702103225.51448-1-gshan@redhat.com (mailing list archive)
State New
Headers show
Series mm/debug_vm_pgtable: Fix corrupted PG_arch_1 by set_pmd_at() | expand

Commit Message

Gavin Shan July 2, 2021, 10:32 a.m. UTC
There are two addresses selected: random virtual address and physical
address corresponding to kernel symbol @start_kernel. During the PMD
tests in pmd_advanced_tests(), the physical address is aligned down
to the starting address of the huge page, whose size is 512MB on ARM64
when we have 64KB base page size. After that, set_pmd_at() is called
to populate the PMD entry. PG_arch_1, PG_dcache_clean on ARM64, is
set to the page flags. Unforunately, the page, corresponding to the
starting address of the huge page could be owned by buddy. It means
PG_arch_1 can be unconditionally set to page owned by buddy.

Afterwards, the page with PG_arch_1 set is fetched from buddy's free
area list, but fails the checking. It leads to the following warning
on ARM64:

   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 calling flush_dcache_page() after each call
to set_{pud, pmd, pte}_at() because PG_arch_1 isn't needed in any case.

Fixes: a5c3b9ffb0f4 ("mm/debug_vm_pgtable: add tests validating advanced arch page table helpers")
Cc: stable@vger.kernel.org # v5.9+
Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

kernel test robot July 2, 2021, 6:10 p.m. UTC | #1
Hi Gavin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to hnaz-linux-mm/master linux/master v5.13 next-20210701]
[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-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 3dbdb38e286903ec220aaf1fb29a8d94297da246
config: x86_64-randconfig-a004-20210702 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 9eb613b2de3163686b1a4bd1160f15ac56a4b083)
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 x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # https://github.com/0day-ci/linux/commit/414db1c0feb54b545b3df56bc19ffff27580deb5
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
        git checkout 414db1c0feb54b545b3df56bc19ffff27580deb5
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> mm/debug_vm_pgtable.c:347:22: error: invalid operands to binary expression ('struct page *' and 'struct page *')
           struct page *page = pfn_to_page(page);
                               ^~~~~~~~~~~~~~~~~
   include/asm-generic/memory_model.h:53:21: note: expanded from macro 'pfn_to_page'
   #define pfn_to_page __pfn_to_page
                       ^
   include/asm-generic/memory_model.h:25:37: note: expanded from macro '__pfn_to_page'
   #define __pfn_to_page(pfn)      (vmemmap + (pfn))
                                    ~~~~~~~ ^ ~~~~~
   1 error generated.


vim +347 mm/debug_vm_pgtable.c

   341	
   342	static void __init pud_advanced_tests(struct mm_struct *mm,
   343					      struct vm_area_struct *vma, pud_t *pudp,
   344					      unsigned long pfn, unsigned long vaddr,
   345					      pgprot_t prot)
   346	{
 > 347		struct page *page = pfn_to_page(page);
   348		pud_t pud;
   349	
   350		if (!has_transparent_hugepage())
   351			return;
   352	
   353		pr_debug("Validating PUD advanced\n");
   354		/* Align the address wrt HPAGE_PUD_SIZE */
   355		vaddr &= HPAGE_PUD_MASK;
   356	
   357		pud = pfn_pud(pfn, prot);
   358		set_pud_at(mm, vaddr, pudp, pud);
   359		flush_dcache_page(page);
   360		pudp_set_wrprotect(mm, vaddr, pudp);
   361		pud = READ_ONCE(*pudp);
   362		WARN_ON(pud_write(pud));
   363	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Gavin Shan July 3, 2021, 12:30 a.m. UTC | #2
On 7/2/21 8:32 PM, Gavin Shan wrote:
> There are two addresses selected: random virtual address and physical
> address corresponding to kernel symbol @start_kernel. During the PMD
> tests in pmd_advanced_tests(), the physical address is aligned down
> to the starting address of the huge page, whose size is 512MB on ARM64
> when we have 64KB base page size. After that, set_pmd_at() is called
> to populate the PMD entry. PG_arch_1, PG_dcache_clean on ARM64, is
> set to the page flags. Unforunately, the page, corresponding to the
> starting address of the huge page could be owned by buddy. It means
> PG_arch_1 can be unconditionally set to page owned by buddy.
> 
> Afterwards, the page with PG_arch_1 set is fetched from buddy's free
> area list, but fails the checking. It leads to the following warning
> on ARM64:
> 
>     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 calling flush_dcache_page() after each call
> to set_{pud, pmd, pte}_at() because PG_arch_1 isn't needed in any case.
> 
> Fixes: a5c3b9ffb0f4 ("mm/debug_vm_pgtable: add tests validating advanced arch page table helpers")
> Cc: stable@vger.kernel.org # v5.9+
> Signed-off-by: Gavin Shan <gshan@redhat.com>
> ---
>   mm/debug_vm_pgtable.c | 16 ++++++++++++++++
>   1 file changed, 16 insertions(+)
> 
> diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
> index 92bfc37300df..7dedf6c6dd25 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>
>   
> @@ -91,6 +93,7 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
>   				      unsigned long pfn, unsigned long vaddr,
>   				      pgprot_t prot)
>   {
> +	struct page *page = pfn_to_page(pfn);
>   	pte_t pte = pfn_pte(pfn, prot);
>   
>   	/*
> @@ -102,6 +105,7 @@ 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);
> +	flush_dcache_page(page);
>   	ptep_set_wrprotect(mm, vaddr, ptep);
>   	pte = ptep_get(ptep);
>   	WARN_ON(pte_write(pte));
> @@ -113,6 +117,7 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
>   	pte = pte_wrprotect(pte);
>   	pte = pte_mkclean(pte);
>   	set_pte_at(mm, vaddr, ptep, pte);
> +	flush_dcache_page(page);
>   	pte = pte_mkwrite(pte);
>   	pte = pte_mkdirty(pte);
>   	ptep_set_access_flags(vma, vaddr, ptep, pte, 1);
> @@ -125,6 +130,7 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
>   	pte = pfn_pte(pfn, prot);
>   	pte = pte_mkyoung(pte);
>   	set_pte_at(mm, vaddr, ptep, pte);
> +	flush_dcache_page(page);
>   	ptep_test_and_clear_young(vma, vaddr, ptep);
>   	pte = ptep_get(ptep);
>   	WARN_ON(pte_young(pte));
> @@ -186,6 +192,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
>   				      unsigned long pfn, unsigned long vaddr,
>   				      pgprot_t prot, pgtable_t pgtable)
>   {
> +	struct page *page = pfn_to_page(pfn);
>   	pmd_t pmd;
>   
>   	if (!has_transparent_hugepage())
> @@ -199,6 +206,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
>   
>   	pmd = pfn_pmd(pfn, prot);
>   	set_pmd_at(mm, vaddr, pmdp, pmd);
> +	flush_dcache_page(page);
>   	pmdp_set_wrprotect(mm, vaddr, pmdp);
>   	pmd = READ_ONCE(*pmdp);
>   	WARN_ON(pmd_write(pmd));
> @@ -210,6 +218,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
>   	pmd = pmd_wrprotect(pmd);
>   	pmd = pmd_mkclean(pmd);
>   	set_pmd_at(mm, vaddr, pmdp, pmd);
> +	flush_dcache_page(page);
>   	pmd = pmd_mkwrite(pmd);
>   	pmd = pmd_mkdirty(pmd);
>   	pmdp_set_access_flags(vma, vaddr, pmdp, pmd, 1);
> @@ -222,6 +231,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
>   	pmd = pmd_mkhuge(pfn_pmd(pfn, prot));
>   	pmd = pmd_mkyoung(pmd);
>   	set_pmd_at(mm, vaddr, pmdp, pmd);
> +	flush_dcache_page(page);
>   	pmdp_test_and_clear_young(vma, vaddr, pmdp);
>   	pmd = READ_ONCE(*pmdp);
>   	WARN_ON(pmd_young(pmd));
> @@ -334,6 +344,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
>   				      unsigned long pfn, unsigned long vaddr,
>   				      pgprot_t prot)
>   {
> +	struct page *page = pfn_to_page(page);
>   	pud_t pud;
>   

Typo here. @page should be replaced by @pfn. I'm holding to post v2 until I
receive comments on v1.

>   	if (!has_transparent_hugepage())
> @@ -345,6 +356,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
>   
>   	pud = pfn_pud(pfn, prot);
>   	set_pud_at(mm, vaddr, pudp, pud);
> +	flush_dcache_page(page);
>   	pudp_set_wrprotect(mm, vaddr, pudp);
>   	pud = READ_ONCE(*pudp);
>   	WARN_ON(pud_write(pud));
> @@ -358,6 +370,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
>   	pud = pud_wrprotect(pud);
>   	pud = pud_mkclean(pud);
>   	set_pud_at(mm, vaddr, pudp, pud);
> +	flush_dcache_page(page);
>   	pud = pud_mkwrite(pud);
>   	pud = pud_mkdirty(pud);
>   	pudp_set_access_flags(vma, vaddr, pudp, pud, 1);
> @@ -373,6 +386,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
>   	pud = pfn_pud(pfn, prot);
>   	pud = pud_mkyoung(pud);
>   	set_pud_at(mm, vaddr, pudp, pud);
> +	flush_dcache_page(page);
>   	pudp_test_and_clear_young(vma, vaddr, pudp);
>   	pud = READ_ONCE(*pudp);
>   	WARN_ON(pud_young(pud));
> @@ -604,6 +618,7 @@ static void __init pte_clear_tests(struct mm_struct *mm, pte_t *ptep,
>   				   unsigned long pfn, unsigned long vaddr,
>   				   pgprot_t prot)
>   {
> +	struct page *page = pfn_to_page(pfn);
>   	pte_t pte = pfn_pte(pfn, prot);
>   
>   	pr_debug("Validating PTE clear\n");
> @@ -611,6 +626,7 @@ static void __init pte_clear_tests(struct mm_struct *mm, pte_t *ptep,
>   	pte = __pte(pte_val(pte) | RANDOM_ORVALUE);
>   #endif
>   	set_pte_at(mm, vaddr, ptep, pte);
> +	flush_dcache_page(page);
>   	barrier();
>   	pte_clear(mm, vaddr, ptep);
>   	pte = ptep_get(ptep);
> 

Thanks,
Gavin
Anshuman Khandual July 5, 2021, 3:59 a.m. UTC | #3
Hello Gavin,

On 7/2/21 4:02 PM, Gavin Shan wrote:
> There are two addresses selected: random virtual address and physical
> address corresponding to kernel symbol @start_kernel. During the PMD
> tests in pmd_advanced_tests(), the physical address is aligned down
> to the starting address of the huge page, whose size is 512MB on ARM64
> when we have 64KB base page size. After that, set_pmd_at() is called
> to populate the PMD entry. PG_arch_1, PG_dcache_clean on ARM64, is
> set to the page flags. Unforunately, the page, corresponding to the
> starting address of the huge page could be owned by buddy. It means
> PG_arch_1 can be unconditionally set to page owned by buddy.
> 
> Afterwards, the page with PG_arch_1 set is fetched from buddy's free
> area list, but fails the checking. It leads to the following warning
> on ARM64:
> 
>    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

Does this problem happen right after the boot ? OR you ran some tests
and workloads to trigger this ? IIRC never seen this before on arm64.
Does this happen on other archs too ?

> 
> This fixes the issue by calling flush_dcache_page() after each call
> to set_{pud, pmd, pte}_at() because PG_arch_1 isn't needed in any case.

This (arm64 specific solution) might cause some side effects on other
platforms ? The solution here needs to be generic enough. I will take
a look into this patch but probably later this week or next week.

- Anshuman
Gavin Shan July 6, 2021, 5:09 a.m. UTC | #4
Hi Anshuman,

On 7/5/21 1:59 PM, Anshuman Khandual wrote:
> On 7/2/21 4:02 PM, Gavin Shan wrote:
>> There are two addresses selected: random virtual address and physical
>> address corresponding to kernel symbol @start_kernel. During the PMD
>> tests in pmd_advanced_tests(), the physical address is aligned down
>> to the starting address of the huge page, whose size is 512MB on ARM64
>> when we have 64KB base page size. After that, set_pmd_at() is called
>> to populate the PMD entry. PG_arch_1, PG_dcache_clean on ARM64, is
>> set to the page flags. Unforunately, the page, corresponding to the
>> starting address of the huge page could be owned by buddy. It means
>> PG_arch_1 can be unconditionally set to page owned by buddy.
>>
>> Afterwards, the page with PG_arch_1 set is fetched from buddy's free
>> area list, but fails the checking. It leads to the following warning
>> on ARM64:
>>
>>     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
> 
> Does this problem happen right after the boot ? OR you ran some tests
> and workloads to trigger this ? IIRC never seen this before on arm64.
> Does this happen on other archs too ?
> 

The page flag (PG_arch_1) is corrupted during boot on ARM64 where
64KB base page size is selected, but the failing page check happens
when the page is pulled from buddy's free area list by "memhog".
I don't think other platform has same issue.

>>
>> This fixes the issue by calling flush_dcache_page() after each call
>> to set_{pud, pmd, pte}_at() because PG_arch_1 isn't needed in any case.
> 
> This (arm64 specific solution) might cause some side effects on other
> platforms ? The solution here needs to be generic enough. I will take
> a look into this patch but probably later this week or next week.
> 

Apart from the overhead of flushing the dcache introduced by flush_dcache_page().
I don't think there is any side-effect. By the way, I'm working on a series
to fix this issue and another issue. I will post the series for review pretty
soon and it's going to fix the following issues:

(1) Current code is organized in relaxed fashion. All information are maintained
     in variables in debug_vm_pgtable(). The variables are passed to test functions.
     It make the code hard to be maintained in long term. So I will introduce a
     dedicated data struct (struct vm_pgtable_debug), as place holder for various
     information.

(2) With the data struct, I'm able to allocate page, to be used by set_{pud, pmd, pte}_at()
     because the target page is accessed on ARM64. The PG_arch_1 flag is set to
     the page and the corresponding iCache is flush if execution permission is given.
     There are two issues if the page used by set_{pud, pmd, pte}_at() wasn't allocated
     from buddy: (a) the PG_arch_1 flag corruption as this patch tries to fix; (b) kernel
     crash because of invalid page fault on accessing the target page. The page isn't
     mapped if CONFIG_DEBUG_PAGEALLOC is enabled.

     start_kernel
     mm_init
     mem_init
     memblock_free_all
     free_low_memory_core_early
     __free_memory_core
     __free_pages_memory
     memblock_free_pages
     __free_pages_core
     __free_pages_ok
     free_pages_prepare
     debug_pagealloc_unmap_pages           # The page is unmapped here

Thanks,
Gavin
kernel test robot July 8, 2021, 12:35 a.m. UTC | #5
Hi Gavin,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to hnaz-linux-mm/master linux/master v5.13 next-20210707]
[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-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 3dbdb38e286903ec220aaf1fb29a8d94297da246
config: x86_64-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/414db1c0feb54b545b3df56bc19ffff27580deb5
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
        git checkout 414db1c0feb54b545b3df56bc19ffff27580deb5
        # 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 <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from arch/x86/include/asm/page.h:76,
                    from arch/x86/include/asm/thread_info.h:12,
                    from include/linux/thread_info.h:59,
                    from arch/x86/include/asm/preempt.h:7,
                    from include/linux/preempt.h:78,
                    from include/linux/spinlock.h:51,
                    from include/linux/mmzone.h:8,
                    from include/linux/gfp.h:6,
                    from mm/debug_vm_pgtable.c:13:
   mm/debug_vm_pgtable.c: In function 'pud_advanced_tests':
>> include/asm-generic/memory_model.h:25:37: error: invalid operands to binary + (have 'struct page *' and 'struct page *')
      25 | #define __pfn_to_page(pfn) (vmemmap + (pfn))
         |                                     ^
   include/asm-generic/memory_model.h:53:21: note: in expansion of macro '__pfn_to_page'
      53 | #define pfn_to_page __pfn_to_page
         |                     ^~~~~~~~~~~~~
   mm/debug_vm_pgtable.c:347:22: note: in expansion of macro 'pfn_to_page'
     347 |  struct page *page = pfn_to_page(page);
         |                      ^~~~~~~~~~~

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for PHY_SPARX5_SERDES
   Depends on (ARCH_SPARX5 || COMPILE_TEST && OF && HAS_IOMEM
   Selected by
   - SPARX5_SWITCH && NETDEVICES && ETHERNET && NET_VENDOR_MICROCHIP && NET_SWITCHDEV && HAS_IOMEM


vim +25 include/asm-generic/memory_model.h

8f6aac419bd590 Christoph Lameter  2007-10-16  23  
af901ca181d92a André Goddard Rosa 2009-11-14  24  /* memmap is virtually contiguous.  */
8f6aac419bd590 Christoph Lameter  2007-10-16 @25  #define __pfn_to_page(pfn)	(vmemmap + (pfn))
32272a26974d20 Martin Schwidefsky 2008-12-25  26  #define __page_to_pfn(page)	(unsigned long)((page) - vmemmap)
8f6aac419bd590 Christoph Lameter  2007-10-16  27  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Anshuman Khandual July 12, 2021, 3:21 a.m. UTC | #6
On 7/8/21 6:05 AM, kernel test robot wrote:
> Hi Gavin,
> 
> Thank you for the patch! Yet something to improve:
> 
> [auto build test ERROR on linus/master]
> [cannot apply to hnaz-linux-mm/master linux/master v5.13 next-20210707]
> [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-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 3dbdb38e286903ec220aaf1fb29a8d94297da246
> config: x86_64-allyesconfig (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
> reproduce (this is a W=1 build):
>         # https://github.com/0day-ci/linux/commit/414db1c0feb54b545b3df56bc19ffff27580deb5
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
>         git checkout 414db1c0feb54b545b3df56bc19ffff27580deb5
>         # 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 <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
>    In file included from arch/x86/include/asm/page.h:76,
>                     from arch/x86/include/asm/thread_info.h:12,
>                     from include/linux/thread_info.h:59,
>                     from arch/x86/include/asm/preempt.h:7,
>                     from include/linux/preempt.h:78,
>                     from include/linux/spinlock.h:51,
>                     from include/linux/mmzone.h:8,
>                     from include/linux/gfp.h:6,
>                     from mm/debug_vm_pgtable.c:13:
>    mm/debug_vm_pgtable.c: In function 'pud_advanced_tests':
>>> include/asm-generic/memory_model.h:25:37: error: invalid operands to binary + (have 'struct page *' and 'struct page *')

Hello Gavin,

So this problem has been fixed in the other series (which now
includes this patch) you have posted ?

- Anshuman

>       25 | #define __pfn_to_page(pfn) (vmemmap + (pfn))
>          |                                     ^
>    include/asm-generic/memory_model.h:53:21: note: in expansion of macro '__pfn_to_page'
>       53 | #define pfn_to_page __pfn_to_page
>          |                     ^~~~~~~~~~~~~
>    mm/debug_vm_pgtable.c:347:22: note: in expansion of macro 'pfn_to_page'
>      347 |  struct page *page = pfn_to_page(page);
>          |                      ^~~~~~~~~~~
> 
> Kconfig warnings: (for reference only)
>    WARNING: unmet direct dependencies detected for PHY_SPARX5_SERDES
>    Depends on (ARCH_SPARX5 || COMPILE_TEST && OF && HAS_IOMEM
>    Selected by
>    - SPARX5_SWITCH && NETDEVICES && ETHERNET && NET_VENDOR_MICROCHIP && NET_SWITCHDEV && HAS_IOMEM
> 
> 
> vim +25 include/asm-generic/memory_model.h
> 
> 8f6aac419bd590 Christoph Lameter  2007-10-16  23  
> af901ca181d92a André Goddard Rosa 2009-11-14  24  /* memmap is virtually contiguous.  */
> 8f6aac419bd590 Christoph Lameter  2007-10-16 @25  #define __pfn_to_page(pfn)	(vmemmap + (pfn))
> 32272a26974d20 Martin Schwidefsky 2008-12-25  26  #define __page_to_pfn(page)	(unsigned long)((page) - vmemmap)
> 8f6aac419bd590 Christoph Lameter  2007-10-16  27  
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
>
Gavin Shan July 12, 2021, 8:24 a.m. UTC | #7
On 7/12/21 1:21 PM, Anshuman Khandual wrote:
> 
> 
> On 7/8/21 6:05 AM, kernel test robot wrote:
>> Hi Gavin,
>>
>> Thank you for the patch! Yet something to improve:
>>
>> [auto build test ERROR on linus/master]
>> [cannot apply to hnaz-linux-mm/master linux/master v5.13 next-20210707]
>> [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-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
>> base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 3dbdb38e286903ec220aaf1fb29a8d94297da246
>> config: x86_64-allyesconfig (attached as .config)
>> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
>> reproduce (this is a W=1 build):
>>          # https://github.com/0day-ci/linux/commit/414db1c0feb54b545b3df56bc19ffff27580deb5
>>          git remote add linux-review https://github.com/0day-ci/linux
>>          git fetch --no-tags linux-review Gavin-Shan/mm-debug_vm_pgtable-Fix-corrupted-PG_arch_1-by-set_pmd_at/20210702-183310
>>          git checkout 414db1c0feb54b545b3df56bc19ffff27580deb5
>>          # 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 <lkp@intel.com>
>>
>> All errors (new ones prefixed by >>):
>>
>>     In file included from arch/x86/include/asm/page.h:76,
>>                      from arch/x86/include/asm/thread_info.h:12,
>>                      from include/linux/thread_info.h:59,
>>                      from arch/x86/include/asm/preempt.h:7,
>>                      from include/linux/preempt.h:78,
>>                      from include/linux/spinlock.h:51,
>>                      from include/linux/mmzone.h:8,
>>                      from include/linux/gfp.h:6,
>>                      from mm/debug_vm_pgtable.c:13:
>>     mm/debug_vm_pgtable.c: In function 'pud_advanced_tests':
>>>> include/asm-generic/memory_model.h:25:37: error: invalid operands to binary + (have 'struct page *' and 'struct page *')
> 
> 
> So this problem has been fixed in the other series (which now
> includes this patch) you have posted ?
> 

Yes, Anshuman. Please ignore this one. The fix has been included into
the following series. The last patch [12/12] of that series fixes the
issue.

[PATCH 00/12] mm/debug_vm_pgtable: Enhancements

Thanks,
Gavin
diff mbox series

Patch

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 92bfc37300df..7dedf6c6dd25 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>
 
@@ -91,6 +93,7 @@  static void __init pte_advanced_tests(struct mm_struct *mm,
 				      unsigned long pfn, unsigned long vaddr,
 				      pgprot_t prot)
 {
+	struct page *page = pfn_to_page(pfn);
 	pte_t pte = pfn_pte(pfn, prot);
 
 	/*
@@ -102,6 +105,7 @@  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);
+	flush_dcache_page(page);
 	ptep_set_wrprotect(mm, vaddr, ptep);
 	pte = ptep_get(ptep);
 	WARN_ON(pte_write(pte));
@@ -113,6 +117,7 @@  static void __init pte_advanced_tests(struct mm_struct *mm,
 	pte = pte_wrprotect(pte);
 	pte = pte_mkclean(pte);
 	set_pte_at(mm, vaddr, ptep, pte);
+	flush_dcache_page(page);
 	pte = pte_mkwrite(pte);
 	pte = pte_mkdirty(pte);
 	ptep_set_access_flags(vma, vaddr, ptep, pte, 1);
@@ -125,6 +130,7 @@  static void __init pte_advanced_tests(struct mm_struct *mm,
 	pte = pfn_pte(pfn, prot);
 	pte = pte_mkyoung(pte);
 	set_pte_at(mm, vaddr, ptep, pte);
+	flush_dcache_page(page);
 	ptep_test_and_clear_young(vma, vaddr, ptep);
 	pte = ptep_get(ptep);
 	WARN_ON(pte_young(pte));
@@ -186,6 +192,7 @@  static void __init pmd_advanced_tests(struct mm_struct *mm,
 				      unsigned long pfn, unsigned long vaddr,
 				      pgprot_t prot, pgtable_t pgtable)
 {
+	struct page *page = pfn_to_page(pfn);
 	pmd_t pmd;
 
 	if (!has_transparent_hugepage())
@@ -199,6 +206,7 @@  static void __init pmd_advanced_tests(struct mm_struct *mm,
 
 	pmd = pfn_pmd(pfn, prot);
 	set_pmd_at(mm, vaddr, pmdp, pmd);
+	flush_dcache_page(page);
 	pmdp_set_wrprotect(mm, vaddr, pmdp);
 	pmd = READ_ONCE(*pmdp);
 	WARN_ON(pmd_write(pmd));
@@ -210,6 +218,7 @@  static void __init pmd_advanced_tests(struct mm_struct *mm,
 	pmd = pmd_wrprotect(pmd);
 	pmd = pmd_mkclean(pmd);
 	set_pmd_at(mm, vaddr, pmdp, pmd);
+	flush_dcache_page(page);
 	pmd = pmd_mkwrite(pmd);
 	pmd = pmd_mkdirty(pmd);
 	pmdp_set_access_flags(vma, vaddr, pmdp, pmd, 1);
@@ -222,6 +231,7 @@  static void __init pmd_advanced_tests(struct mm_struct *mm,
 	pmd = pmd_mkhuge(pfn_pmd(pfn, prot));
 	pmd = pmd_mkyoung(pmd);
 	set_pmd_at(mm, vaddr, pmdp, pmd);
+	flush_dcache_page(page);
 	pmdp_test_and_clear_young(vma, vaddr, pmdp);
 	pmd = READ_ONCE(*pmdp);
 	WARN_ON(pmd_young(pmd));
@@ -334,6 +344,7 @@  static void __init pud_advanced_tests(struct mm_struct *mm,
 				      unsigned long pfn, unsigned long vaddr,
 				      pgprot_t prot)
 {
+	struct page *page = pfn_to_page(page);
 	pud_t pud;
 
 	if (!has_transparent_hugepage())
@@ -345,6 +356,7 @@  static void __init pud_advanced_tests(struct mm_struct *mm,
 
 	pud = pfn_pud(pfn, prot);
 	set_pud_at(mm, vaddr, pudp, pud);
+	flush_dcache_page(page);
 	pudp_set_wrprotect(mm, vaddr, pudp);
 	pud = READ_ONCE(*pudp);
 	WARN_ON(pud_write(pud));
@@ -358,6 +370,7 @@  static void __init pud_advanced_tests(struct mm_struct *mm,
 	pud = pud_wrprotect(pud);
 	pud = pud_mkclean(pud);
 	set_pud_at(mm, vaddr, pudp, pud);
+	flush_dcache_page(page);
 	pud = pud_mkwrite(pud);
 	pud = pud_mkdirty(pud);
 	pudp_set_access_flags(vma, vaddr, pudp, pud, 1);
@@ -373,6 +386,7 @@  static void __init pud_advanced_tests(struct mm_struct *mm,
 	pud = pfn_pud(pfn, prot);
 	pud = pud_mkyoung(pud);
 	set_pud_at(mm, vaddr, pudp, pud);
+	flush_dcache_page(page);
 	pudp_test_and_clear_young(vma, vaddr, pudp);
 	pud = READ_ONCE(*pudp);
 	WARN_ON(pud_young(pud));
@@ -604,6 +618,7 @@  static void __init pte_clear_tests(struct mm_struct *mm, pte_t *ptep,
 				   unsigned long pfn, unsigned long vaddr,
 				   pgprot_t prot)
 {
+	struct page *page = pfn_to_page(pfn);
 	pte_t pte = pfn_pte(pfn, prot);
 
 	pr_debug("Validating PTE clear\n");
@@ -611,6 +626,7 @@  static void __init pte_clear_tests(struct mm_struct *mm, pte_t *ptep,
 	pte = __pte(pte_val(pte) | RANDOM_ORVALUE);
 #endif
 	set_pte_at(mm, vaddr, ptep, pte);
+	flush_dcache_page(page);
 	barrier();
 	pte_clear(mm, vaddr, ptep);
 	pte = ptep_get(ptep);