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: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Родитель
13bd817bb8
Коммит
7b868e81be
|
@ -689,27 +689,34 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
|
||||||
struct page *
|
struct page *
|
||||||
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
|
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
|
||||||
{
|
{
|
||||||
pte_t *ptep;
|
pte_t *ptep, pte;
|
||||||
struct page *page;
|
|
||||||
unsigned shift;
|
unsigned shift;
|
||||||
unsigned long mask, flags;
|
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
|
* Transparent hugepages are handled by generic code. We can skip them
|
||||||
* here.
|
* here.
|
||||||
*/
|
*/
|
||||||
local_irq_save(flags);
|
if (!shift || pmd_trans_huge(__pmd(pte_val(pte))))
|
||||||
ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
|
goto no_page;
|
||||||
|
|
||||||
/* Verify it is a huge page else bail. */
|
if (!pte_present(pte)) {
|
||||||
if (!ptep || !shift || pmd_trans_huge(*(pmd_t *)ptep)) {
|
page = NULL;
|
||||||
local_irq_restore(flags);
|
goto no_page;
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
}
|
||||||
mask = (1UL << shift) - 1;
|
mask = (1UL << shift) - 1;
|
||||||
page = pte_page(*ptep);
|
page = pte_page(pte);
|
||||||
if (page)
|
if (page)
|
||||||
page += (address & mask) / PAGE_SIZE;
|
page += (address & mask) / PAGE_SIZE;
|
||||||
|
|
||||||
|
no_page:
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче