On sparc64, pte_clear_not_present_full() nowadays does a simple __set_pte_at(). In __set_pte_at() -> maybe_tlb_batch_add(), we check pte_accessible() to see whether to call tlb_batch_add(). However, non-present PTEs are surely not accessible, so tlb_batch_add() is never called and the "full" parameter is irrelevant. Let's drop the helper and just let common code do a pte_clear(). pte_clear() on sparc64 maps to set_pte_at()->set_ptes()->__set_pte_at() ... so it ends up calling the same function, just with "full=0". Given that "full" is irrelevant, there is no change. We added pte_clear_not_present_full() for sparc64 in commit 90f08e399d05 ("sparc: mmu_gather rework"), and I suspect that it was already not required back then. Cc: Peter Zijlstra Signed-off-by: David Hildenbrand (Arm) --- arch/sparc/include/asm/pgtable_64.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 74ede706fb325..0837ebbc5dce6 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -945,10 +945,6 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, #define pte_clear(mm,addr,ptep) \ set_pte_at((mm), (addr), (ptep), __pte(0UL)) -#define __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL -#define pte_clear_not_present_full(mm,addr,ptep,fullmm) \ - __set_pte_at((mm), (addr), (ptep), __pte(0UL), (fullmm)) - #ifdef DCACHE_ALIASING_POSSIBLE #define __HAVE_ARCH_MOVE_PTE #define move_pte(pte, old_addr, new_addr) \ -- 2.43.0 In general, there is no good reason to do anything special when clearing non-present PTEs. In theory, HW that does have to invalidate TLBs for non-present PTEs could benefit from a "full" parameter, but fortunately pte_clear_not_present_full() is not wired up anymore ... and there would have to be something very convincing for us to care about that to re-add it. So, let's just use pte_clear() directly now. To avoid the compiler complaining on some configs about unused "addr" parameter, silence that here. Reviewed-by: Oscar Salvador (SUSE) Signed-off-by: David Hildenbrand (Arm) --- include/linux/pgtable.h | 21 ++++----------------- mm/madvise.c | 4 ++-- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index dc804296d78f7..0b81e396816a5 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -988,21 +988,6 @@ static inline void update_mmu_tlb(struct vm_area_struct *vma, update_mmu_tlb_range(vma, address, ptep, 1); } -/* - * Some architectures may be able to avoid expensive synchronization - * primitives when modifications are made to PTE's which are already - * not present, or in the process of an address space destruction. - */ -#ifndef __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL -static inline void pte_clear_not_present_full(struct mm_struct *mm, - unsigned long address, - pte_t *ptep, - int full) -{ - pte_clear(mm, address, ptep); -} -#endif - #ifndef clear_not_present_full_ptes /** * clear_not_present_full_ptes - Clear multiple not present PTEs which are @@ -1014,7 +999,7 @@ static inline void pte_clear_not_present_full(struct mm_struct *mm, * @full: Whether we are clearing a full mm. * * May be overridden by the architecture; otherwise, implemented as a simple - * loop over pte_clear_not_present_full(). + * loop over pte_clear(). * * Context: The caller holds the page table lock. The PTEs are all not present. * The PTEs are all in the same PMD. @@ -1022,8 +1007,10 @@ static inline void pte_clear_not_present_full(struct mm_struct *mm, static inline void clear_not_present_full_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep, unsigned int nr, int full) { + (void)addr; + for (;;) { - pte_clear_not_present_full(mm, addr, ptep, full); + pte_clear(mm, addr, ptep); if (--nr == 0) break; ptep++; diff --git a/mm/madvise.c b/mm/madvise.c index cd9bb077072cc..f3cda54c1d6a0 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -698,7 +698,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, clear_not_present_full_ptes(mm, addr, pte, nr, tlb->fullmm); } else if (softleaf_is_hwpoison(entry) || softleaf_is_poison_marker(entry)) { - pte_clear_not_present_full(mm, addr, pte, tlb->fullmm); + pte_clear(mm, addr, pte); } continue; } @@ -1234,7 +1234,7 @@ static int guard_remove_pte_entry(pte_t *pte, unsigned long addr, if (is_guard_pte_marker(ptent)) { /* Simply clear the PTE marker. */ - pte_clear_not_present_full(walk->mm, addr, pte, false); + pte_clear(walk->mm, addr, pte); update_mmu_cache(walk->vma, addr, pte); } -- 2.43.0 Let's clean it up a bit: (1) There is no need to pass "full" anymore. (2) No architecture overwrites it, and there isn't really a good reason to do so when dealing with non-resent PTEs. (3) While at it, call it "non-present", similar to copy_nonpresent_pte() and zap_nonpresent_ptes(). It's a shame that we have clear_non_present_ptes() correspond to pte_clear() and clear_ptes() correspond to ptep_get_and_clear*(). Reviewed-by: Oscar Salvador (SUSE) Signed-off-by: David Hildenbrand (Arm) --- include/linux/pgtable.h | 14 ++++---------- mm/madvise.c | 2 +- mm/memory.c | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index 0b81e396816a5..d52d2a976e5a2 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -988,24 +988,19 @@ static inline void update_mmu_tlb(struct vm_area_struct *vma, update_mmu_tlb_range(vma, address, ptep, 1); } -#ifndef clear_not_present_full_ptes /** - * clear_not_present_full_ptes - Clear multiple not present PTEs which are - * consecutive in the pgtable. + * clear_nonpresent_ptes - Clear multiple non-present PTEs which are + * consecutive in the pgtable. * @mm: Address space the ptes represent. * @addr: Address of the first pte. * @ptep: Page table pointer for the first entry. * @nr: Number of entries to clear. - * @full: Whether we are clearing a full mm. - * - * May be overridden by the architecture; otherwise, implemented as a simple - * loop over pte_clear(). * * Context: The caller holds the page table lock. The PTEs are all not present. * The PTEs are all in the same PMD. */ -static inline void clear_not_present_full_ptes(struct mm_struct *mm, - unsigned long addr, pte_t *ptep, unsigned int nr, int full) +static inline void clear_nonpresent_ptes(struct mm_struct *mm, + unsigned long addr, pte_t *ptep, unsigned int nr) { (void)addr; @@ -1017,7 +1012,6 @@ static inline void clear_not_present_full_ptes(struct mm_struct *mm, addr += PAGE_SIZE; } } -#endif #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH extern pte_t ptep_clear_flush(struct vm_area_struct *vma, diff --git a/mm/madvise.c b/mm/madvise.c index f3cda54c1d6a0..3db143c442eaa 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -695,7 +695,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, nr = swap_pte_batch(pte, max_nr, ptent); nr_swap -= nr; swap_put_entries_direct(entry, nr); - clear_not_present_full_ptes(mm, addr, pte, nr, tlb->fullmm); + clear_nonpresent_ptes(mm, addr, pte, nr); } else if (softleaf_is_hwpoison(entry) || softleaf_is_poison_marker(entry)) { pte_clear(mm, addr, pte); diff --git a/mm/memory.c b/mm/memory.c index ff338c2abe923..a3fcaf8cfe8f8 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1797,7 +1797,7 @@ static inline int zap_nonpresent_ptes(struct mmu_gather *tlb, pr_alert("unrecognized swap entry 0x%lx\n", entry.val); WARN_ON_ONCE(1); } - clear_not_present_full_ptes(vma->vm_mm, addr, pte, nr, tlb->fullmm); + clear_nonpresent_ptes(vma->vm_mm, addr, pte, nr); *any_skipped = zap_install_uffd_wp_if_needed(vma, addr, pte, nr, details, ptent); return nr; -- 2.43.0