Skip to content

Commit 07509e1

Browse files
committed
arm64: pgtable: Fix pte_accessible()
pte_accessible() is used by ptep_clear_flush() to figure out whether TLB invalidation is necessary when unmapping pages for reclaim. Although our implementation is correct according to the architecture, returning true only for valid, young ptes in the absence of racing page-table modifications, this is in fact flawed due to lazy invalidation of old ptes in ptep_clear_flush_young() where we elide the expensive DSB instruction for completing the TLB invalidation. Rather than penalise the aging path, adjust pte_accessible() to return true for any valid pte, even if the access flag is cleared. Cc: <[email protected]> Fixes: 76c714b ("arm64: pgtable: implement pte_accessible()") Reported-by: Yu Zhao <[email protected]> Acked-by: Yu Zhao <[email protected]> Reviewed-by: Minchan Kim <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 774c4a3 commit 07509e1

File tree

1 file changed

+4
-3
lines changed

1 file changed

+4
-3
lines changed

arch/arm64/include/asm/pgtable.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,19 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
115115
#define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID))
116116
#define pte_valid_not_user(pte) \
117117
((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
118-
#define pte_valid_young(pte) \
119-
((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
120118
#define pte_valid_user(pte) \
121119
((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
122120

123121
/*
124122
* Could the pte be present in the TLB? We must check mm_tlb_flush_pending
125123
* so that we don't erroneously return false for pages that have been
126124
* remapped as PROT_NONE but are yet to be flushed from the TLB.
125+
* Note that we can't make any assumptions based on the state of the access
126+
* flag, since ptep_clear_flush_young() elides a DSB when invalidating the
127+
* TLB.
127128
*/
128129
#define pte_accessible(mm, pte) \
129-
(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte))
130+
(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte))
130131

131132
/*
132133
* p??_access_permitted() is true for valid user mappings (subject to the

0 commit comments

Comments
 (0)