diff options
Diffstat (limited to 'mm/page_vma_mapped.c')
| -rw-r--r-- | mm/page_vma_mapped.c | 29 | 
1 files changed, 12 insertions, 17 deletions
| diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c index 6a03946469a9..d22b84310f6d 100644 --- a/mm/page_vma_mapped.c +++ b/mm/page_vma_mapped.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  #include <linux/mm.h>  #include <linux/rmap.h>  #include <linux/hugetlb.h> @@ -6,17 +7,6 @@  #include "internal.h" -static inline bool check_pmd(struct page_vma_mapped_walk *pvmw) -{ -	pmd_t pmde; -	/* -	 * Make sure we don't re-load pmd between present and !trans_huge check. -	 * We need a consistent view. -	 */ -	pmde = READ_ONCE(*pvmw->pmd); -	return pmd_present(pmde) && !pmd_trans_huge(pmde); -} -  static inline bool not_found(struct page_vma_mapped_walk *pvmw)  {  	page_vma_mapped_walk_done(pvmw); @@ -116,6 +106,7 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)  	pgd_t *pgd;  	p4d_t *p4d;  	pud_t *pud; +	pmd_t pmde;  	/* The only possible pmd mapping has been handled on last iteration */  	if (pvmw->pmd && !pvmw->pte) @@ -148,7 +139,13 @@ restart:  	if (!pud_present(*pud))  		return false;  	pvmw->pmd = pmd_offset(pud, pvmw->address); -	if (pmd_trans_huge(*pvmw->pmd) || is_pmd_migration_entry(*pvmw->pmd)) { +	/* +	 * Make sure the pmd value isn't cached in a register by the +	 * compiler and used as a stale value after we've observed a +	 * subsequent update. +	 */ +	pmde = READ_ONCE(*pvmw->pmd); +	if (pmd_trans_huge(pmde) || is_pmd_migration_entry(pmde)) {  		pvmw->ptl = pmd_lock(mm, pvmw->pmd);  		if (likely(pmd_trans_huge(*pvmw->pmd))) {  			if (pvmw->flags & PVMW_MIGRATION) @@ -167,17 +164,15 @@ restart:  						return not_found(pvmw);  					return true;  				} -			} else -				WARN_ONCE(1, "Non present huge pmd without pmd migration enabled!"); +			}  			return not_found(pvmw);  		} else {  			/* THP pmd was split under us: handle on pte level */  			spin_unlock(pvmw->ptl);  			pvmw->ptl = NULL;  		} -	} else { -		if (!check_pmd(pvmw)) -			return false; +	} else if (!pmd_present(pmde)) { +		return false;  	}  	if (!map_pte(pvmw))  		goto next_pte; |