Commit 02410ac7 authored by Ryan Roberts's avatar Ryan Roberts Committed by Will Deacon
Browse files

mm: hugetlb: Add huge page size param to huge_ptep_get_and_clear()



In order to fix a bug, arm64 needs to be told the size of the huge page
for which the huge_pte is being cleared in huge_ptep_get_and_clear().
Provide for this by adding an `unsigned long sz` parameter to the
function. This follows the same pattern as huge_pte_clear() and
set_huge_pte_at().

This commit makes the required interface modifications to the core mm as
well as all arches that implement this function (arm64, loongarch, mips,
parisc, powerpc, riscv, s390, sparc). The actual arm64 bug will be fixed
in a separate commit.

Cc: stable@vger.kernel.org
Fixes: 66b3923a ("arm64: hugetlb: add support for PTE contiguous bit")
Acked-by: default avatarDavid Hildenbrand <david@redhat.com>
Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com> # riscv
Reviewed-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Reviewed-by: default avatarAnshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: default avatarRyan Roberts <ryan.roberts@arm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com> # s390
Link: https://lore.kernel.org/r/20250226120656.2400136-2-ryan.roberts@arm.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 2b1283e1
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -42,8 +42,8 @@ extern int huge_ptep_set_access_flags(struct vm_area_struct *vma,
				      unsigned long addr, pte_t *ptep,
				      pte_t pte, int dirty);
#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
				     unsigned long addr, pte_t *ptep);
extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
				     pte_t *ptep, unsigned long sz);
#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT
extern void huge_ptep_set_wrprotect(struct mm_struct *mm,
				    unsigned long addr, pte_t *ptep);
+5 −3
Original line number Diff line number Diff line
@@ -396,8 +396,8 @@ void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
		__pte_clear(mm, addr, ptep);
}

pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
			      unsigned long addr, pte_t *ptep)
pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
			      pte_t *ptep, unsigned long sz)
{
	int ncontig;
	size_t pgsize;
@@ -549,6 +549,8 @@ bool __init arch_hugetlb_valid_size(unsigned long size)

pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
{
	unsigned long psize = huge_page_size(hstate_vma(vma));

	if (alternative_has_cap_unlikely(ARM64_WORKAROUND_2645198)) {
		/*
		 * Break-before-make (BBM) is required for all user space mappings
@@ -558,7 +560,7 @@ pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr
		if (pte_user_exec(__ptep_get(ptep)))
			return huge_ptep_clear_flush(vma, addr, ptep);
	}
	return huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
	return huge_ptep_get_and_clear(vma->vm_mm, addr, ptep, psize);
}

void huge_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
+4 −2
Original line number Diff line number Diff line
@@ -36,7 +36,8 @@ static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,

#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
					    unsigned long addr, pte_t *ptep)
					    unsigned long addr, pte_t *ptep,
					    unsigned long sz)
{
	pte_t clear;
	pte_t pte = ptep_get(ptep);
@@ -51,8 +52,9 @@ static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
					  unsigned long addr, pte_t *ptep)
{
	pte_t pte;
	unsigned long sz = huge_page_size(hstate_vma(vma));

	pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
	pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep, sz);
	flush_tlb_page(vma, addr);
	return pte;
}
+4 −2
Original line number Diff line number Diff line
@@ -27,7 +27,8 @@ static inline int prepare_hugepage_range(struct file *file,

#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
					    unsigned long addr, pte_t *ptep)
					    unsigned long addr, pte_t *ptep,
					    unsigned long sz)
{
	pte_t clear;
	pte_t pte = *ptep;
@@ -42,13 +43,14 @@ static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
					  unsigned long addr, pte_t *ptep)
{
	pte_t pte;
	unsigned long sz = huge_page_size(hstate_vma(vma));

	/*
	 * clear the huge pte entry firstly, so that the other smp threads will
	 * not get old pte entry after finishing flush_tlb_page and before
	 * setting new huge pte entry
	 */
	pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
	pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep, sz);
	flush_tlb_page(vma, addr);
	return pte;
}
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,

#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
			      pte_t *ptep);
			      pte_t *ptep, unsigned long sz);

#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH
static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
Loading