Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b868e81 authored by Aneesh Kumar K.V's avatar Aneesh Kumar K.V Committed by Michael Ellerman
Browse files

powerpc/mm: Return NULL for not present hugetlb page



We need to check whether pte is present in follow_huge_addr() and
properly return NULL if mapping is not present. Also use READ_ONCE
when dereferencing pte_t address.

Without this patch, we may wrongly return a zero pfn page in
follow_huge_addr().

Reviewed-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 13bd817b
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -689,27 +689,34 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
{
	pte_t *ptep;
	struct page *page;
	pte_t *ptep, pte;
	unsigned shift;
	unsigned long mask, flags;
	struct page *page = ERR_PTR(-EINVAL);

	local_irq_save(flags);
	ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
	if (!ptep)
		goto no_page;
	pte = READ_ONCE(*ptep);
	/*
	 * Verify it is a huge page else bail.
	 * Transparent hugepages are handled by generic code. We can skip them
	 * here.
	 */
	local_irq_save(flags);
	ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
	if (!shift || pmd_trans_huge(__pmd(pte_val(pte))))
		goto no_page;

	/* Verify it is a huge page else bail. */
	if (!ptep || !shift || pmd_trans_huge(*(pmd_t *)ptep)) {
		local_irq_restore(flags);
		return ERR_PTR(-EINVAL);
	if (!pte_present(pte)) {
		page = NULL;
		goto no_page;
	}
	mask = (1UL << shift) - 1;
	page = pte_page(*ptep);
	page = pte_page(pte);
	if (page)
		page += (address & mask) / PAGE_SIZE;

no_page:
	local_irq_restore(flags);
	return page;
}