From: Adam Litke Initial Post (Wed, 17 Aug 2005) This patch moves the if (! pte_none(*pte)) hugetlb_clean_stale_pgtable(pte); logic into huge_pte_alloc() so all of its callers can be immune to the bug described by Kenneth Chen at http://lkml.org/lkml/2004/6/16/246 > It turns out there is a bug in hugetlb_prefault(): with 3 level page table, > huge_pte_alloc() might return a pmd that points to a PTE page. It happens > if the virtual address for hugetlb mmap is recycled from previously used > normal page mmap. free_pgtables() might not scrub the pmd entry on > munmap and hugetlb_prefault skips on any pmd presence regardless what type > it is. Unless I am missing something, it seems more correct to place the check inside huge_pte_alloc() to prevent a the same bug wherever a huge pte is allocated. It also allows checking for this condition when lazily faulting huge pages later in the series. Signed-off-by: Adam Litke Cc: Signed-off-by: Andrew Morton --- arch/i386/mm/hugetlbpage.c | 13 +++++++++++-- mm/hugetlb.c | 2 -- 2 files changed, 11 insertions(+), 4 deletions(-) diff -puN arch/i386/mm/hugetlbpage.c~hugetlb-move-stale-pte-check-into-huge_pte_alloc arch/i386/mm/hugetlbpage.c --- 25/arch/i386/mm/hugetlbpage.c~hugetlb-move-stale-pte-check-into-huge_pte_alloc Mon Aug 29 15:48:03 2005 +++ 25-akpm/arch/i386/mm/hugetlbpage.c Mon Aug 29 15:48:03 2005 @@ -22,12 +22,21 @@ pte_t *huge_pte_alloc(struct mm_struct * { pgd_t *pgd; pud_t *pud; - pmd_t *pmd = NULL; + pmd_t *pmd; + pte_t *pte = NULL; pgd = pgd_offset(mm, addr); pud = pud_alloc(mm, pgd, addr); pmd = pmd_alloc(mm, pud, addr); - return (pte_t *) pmd; + + if (!pmd) + goto out; + + pte = (pte_t *) pmd; + if (!pte_none(*pte) && !pte_huge(*pte)) + hugetlb_clean_stale_pgtable(pte); +out: + return pte; } pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) diff -puN mm/hugetlb.c~hugetlb-move-stale-pte-check-into-huge_pte_alloc mm/hugetlb.c --- 25/mm/hugetlb.c~hugetlb-move-stale-pte-check-into-huge_pte_alloc Mon Aug 29 15:48:03 2005 +++ 25-akpm/mm/hugetlb.c Mon Aug 29 15:48:03 2005 @@ -360,8 +360,6 @@ int hugetlb_prefault(struct address_spac ret = -ENOMEM; goto out; } - if (! pte_none(*pte)) - hugetlb_clean_stale_pgtable(pte); idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); _