Re: [Hugetlb x86] 2/3 Move stale pte check into huge_pte_alloc()

From: Adam Litke (agl_at_us.ibm.com)
Date: 08/23/05

  • Next message: Adam Litke: "Re: [Hugetlb x86] 3/3 Check p?d_present in huge_pte_offset()"
    To: akpm@osdl.org
    Date:	Tue, 23 Aug 2005 13:06:07 -0500
    
    

    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.

    Diffed against 2.6.13-rc6

    Signed-off-by: Adam Litke <agl@us.ibm.com>

    ---
     arch/i386/mm/hugetlbpage.c |   13 +++++++++++--
     mm/hugetlb.c               |    2 --
     2 files changed, 11 insertions(+), 4 deletions(-)
    diff -upN reference/arch/i386/mm/hugetlbpage.c current/arch/i386/mm/hugetlbpage.c
    --- reference/arch/i386/mm/hugetlbpage.c
    +++ current/arch/i386/mm/hugetlbpage.c
    @@ -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 -upN reference/mm/hugetlb.c current/mm/hugetlb.c
    --- reference/mm/hugetlb.c
    +++ current/mm/hugetlb.c
    @@ -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));
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at  http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at  http://www.tux.org/lkml/
    

  • Next message: Adam Litke: "Re: [Hugetlb x86] 3/3 Check p?d_present in huge_pte_offset()"

    Relevant Pages