[PATCH 09/46] mm/rmap: handle device-exclusive entries in folio_referenced_one()

Dev Jain dev.jain at arm.com
Wed Oct 28 00:51:55 PDT 2026



On 27/10/26 4:47 am, David Hildenbrand (Arm) wrote:
> page_vma_mapped_walk() can return non-present device-exclusive entries,
> but folio_referenced_one() passes them to PTE young-bit accessors that
> require present PTEs.
> 
> We must neither call clear_flush_young_ptes_notify() nor
> folio_pte_batch() with non-present entries. For example, clearing the
> young bit on non-present PTEs can corrupt the entry: on arm64
> PTE_AF overlaps the swap type, so clearing it turns a device-exclusive
> entry into an ordinary swap entry.
> 
> folio_pte_batch() will VM_WARN_ON_FOLIO.
> 
> Apply the same approach as the previous fixes to e.g., damon_ptep_mkold():
> treat these entries as old from the CPU's perspective and obtain their
> young state through the MMU notifier.
> 
> Skip PTE batching and MGLRU look-around for non-present entries, and
> don't modify non-present PTEs.
> 
> Fixes: b756a3b5e7ea ("mm: device exclusive memory access")
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs at kernel.org>
> Cc: stable at vger.kernel.org
> Reported-by: Josef Bacik <josef at toxicpanda.com>
> Signed-off-by: David Hildenbrand (Arm) <david at kernel.org>
> ---

Reviewed-by: Dev Jain <dev.jain at arm.com>

But nit below.


>  mm/rmap.c | 23 +++++++++++++++++++----
>  1 file changed, 19 insertions(+), 4 deletions(-)
> 
> diff --git a/mm/rmap.c b/mm/rmap.c
> index 1131b76bbbc28..0faef46806e5c 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -924,6 +924,7 @@ static bool folio_referenced_one(struct folio *folio,
>  	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
>  	int ptes = 0, referenced = 0;
>  	unsigned int nr;
> +	pte_t pteval;
>  
>  	while (page_vma_mapped_walk(&pvmw)) {
>  		address = pvmw.address;
> @@ -968,10 +969,12 @@ static bool folio_referenced_one(struct folio *folio,
>  			return false;
>  		}
>  
> -		if (pvmw.pte && folio_test_large(folio)) {
> +		if (pvmw.pte)
> +			pteval = ptep_get(pvmw.pte);
> +
> +		if (pvmw.pte && pte_present(pteval) && folio_test_large(folio)) {
>  			const unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
>  			const unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
> -			pte_t pteval = ptep_get(pvmw.pte);
>  
>  			nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
>  		}
> @@ -981,11 +984,23 @@ static bool folio_referenced_one(struct folio *folio,
>  		 * are. —they could be on active/inactive lists or on MGLRU. So the
>  		 * simplest approach is to disable this look-around optimization.
>  		 */
> -		if (lru_gen_enabled() && !lru_gen_switching() && pvmw.pte) {
> +		if (lru_gen_enabled() && !lru_gen_switching() && pvmw.pte &&
> +		    pte_present(pteval)) {
>  			if (lru_gen_look_around(&pvmw, nr))
>  				referenced++;
>  		} else if (pvmw.pte) {
> -			if (clear_flush_young_ptes_notify(vma, address, pvmw.pte, nr))
> +			bool young = false;
> +
> +			/*
> +			 * PFN swap PTEs, such as device-exclusive ones, that

You mean "PFN softleaf PTEs"? Better expressed as "softleaf PTEs embedding a PFN" ...


> +			 * actually map pages are "old" from a CPU perspective.
> +			 * The MMU notifier takes care of any device aspects.
> +			 */
> +			if (pte_present(pteval))
> +				young = clear_flush_young_ptes(vma, address, pvmw.pte, nr);
> +			young |= mmu_notifier_clear_flush_young(vma->vm_mm, address,
> +								address + nr * PAGE_SIZE);
> +			if (young)
>  				referenced++;
>  		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
>  			if (pmdp_clear_flush_young_notify(vma, address,
> 




More information about the kexec mailing list