There is a problem now: CPU 0 CPU 1 pmdp_invalidate do_page_fault ... __handle_mm_fault is_swap_pmd == true trigger VM_BUG_ON() ? set_pmd_at the reason is when a pmd entry is invalidated by pmd_mkinvalid, pmd_present should return true but now pmd_present return false. Like arm64 does in commit b65399f6111b ("arm64/mm: Change THP helpers to comply with generic MM semantics"). we introduce a _PMD_PRESENT_INVALID_SHIFT bit to check if a pmd is present but invalidated by pmd_mkinvalid. After this commit pmd_present will return the correct value and the VM_BUG_ON will not be triggered. Signed-off-by: Hongchen Zhang <zhanghongchen@xxxxxxxxxxx> --- arch/mips/include/asm/pgtable-64.h | 2 +- arch/mips/include/asm/pgtable-bits.h | 2 ++ arch/mips/include/asm/pgtable.h | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h index 41921ac..050cf66 100644 --- a/arch/mips/include/asm/pgtable-64.h +++ b/arch/mips/include/asm/pgtable-64.h @@ -265,7 +265,7 @@ static inline int pmd_present(pmd_t pmd) { #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT if (unlikely(pmd_val(pmd) & _PAGE_HUGE)) - return pmd_val(pmd) & _PAGE_PRESENT; + return pmd_val(pmd) & (_PAGE_PRESENT | _PMD_PRESENT_INVALID); #endif return pmd_val(pmd) != (unsigned long) invalid_pte_table; diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index 2362842..72cd88a 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -130,6 +130,7 @@ enum pgtable_bits { _PAGE_MODIFIED_SHIFT, #if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) _PAGE_HUGE_SHIFT, + _PMD_PRESENT_INVALID_SHIFT, #endif #if defined(CONFIG_ARCH_HAS_PTE_SPECIAL) _PAGE_SPECIAL_SHIFT, @@ -157,6 +158,7 @@ enum pgtable_bits { #define _PAGE_MODIFIED (1 << _PAGE_MODIFIED_SHIFT) #if defined(CONFIG_MIPS_HUGE_TLB_SUPPORT) # define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) +#define _PMD_PRESENT_INVALID (1 << _PMD_PRESENT_INVALID_SHIFT) #endif #if defined(CONFIG_ARCH_HAS_PTE_SPECIAL) # define _PAGE_SPECIAL (1 << _PAGE_SPECIAL_SHIFT) diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 374c632..a75f461 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -696,12 +696,15 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) return pmd; } +#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT static inline pmd_t pmd_mkinvalid(pmd_t pmd) { + pmd_val(pmd) |= _PMD_PRESENT_INVALID; pmd_val(pmd) &= ~(_PAGE_PRESENT | _PAGE_VALID | _PAGE_DIRTY); return pmd; } +#endif /* * The generic version pmdp_huge_get_and_clear uses a version of pmd_clear() with a -- 1.8.3.1