diff options
Diffstat (limited to 'mm/hugetlb.c')
| -rw-r--r-- | mm/hugetlb.c | 39 | 
1 files changed, 25 insertions, 14 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index a7aa811b7d14..e5828875f7bb 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -4403,7 +4403,9 @@ int hugetlb_reserve_pages(struct inode *inode,  	return 0;  out_err:  	if (!vma || vma->vm_flags & VM_MAYSHARE) -		region_abort(resv_map, from, to); +		/* Don't call region_abort if region_chg failed */ +		if (chg >= 0) +			region_abort(resv_map, from, to);  	if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER))  		kref_put(&resv_map->refs, resv_map_release);  	return ret; @@ -4555,7 +4557,8 @@ out:  int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)  {  	pgd_t *pgd = pgd_offset(mm, *addr); -	pud_t *pud = pud_offset(pgd, *addr); +	p4d_t *p4d = p4d_offset(pgd, *addr); +	pud_t *pud = pud_offset(p4d, *addr);  	BUG_ON(page_count(virt_to_page(ptep)) == 0);  	if (page_count(virt_to_page(ptep)) == 1) @@ -4586,11 +4589,13 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,  			unsigned long addr, unsigned long sz)  {  	pgd_t *pgd; +	p4d_t *p4d;  	pud_t *pud;  	pte_t *pte = NULL;  	pgd = pgd_offset(mm, addr); -	pud = pud_alloc(mm, pgd, addr); +	p4d = p4d_offset(pgd, addr); +	pud = pud_alloc(mm, p4d, addr);  	if (pud) {  		if (sz == PUD_SIZE) {  			pte = (pte_t *)pud; @@ -4610,18 +4615,22 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,  pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)  {  	pgd_t *pgd; +	p4d_t *p4d;  	pud_t *pud; -	pmd_t *pmd = NULL; +	pmd_t *pmd;  	pgd = pgd_offset(mm, addr); -	if (pgd_present(*pgd)) { -		pud = pud_offset(pgd, addr); -		if (pud_present(*pud)) { -			if (pud_huge(*pud)) -				return (pte_t *)pud; -			pmd = pmd_offset(pud, addr); -		} -	} +	if (!pgd_present(*pgd)) +		return NULL; +	p4d = p4d_offset(pgd, addr); +	if (!p4d_present(*p4d)) +		return NULL; +	pud = pud_offset(p4d, addr); +	if (!pud_present(*pud)) +		return NULL; +	if (pud_huge(*pud)) +		return (pte_t *)pud; +	pmd = pmd_offset(pud, addr);  	return (pte_t *) pmd;  } @@ -4644,6 +4653,7 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,  {  	struct page *page = NULL;  	spinlock_t *ptl; +	pte_t pte;  retry:  	ptl = pmd_lockptr(mm, pmd);  	spin_lock(ptl); @@ -4653,12 +4663,13 @@ retry:  	 */  	if (!pmd_huge(*pmd))  		goto out; -	if (pmd_present(*pmd)) { +	pte = huge_ptep_get((pte_t *)pmd); +	if (pte_present(pte)) {  		page = pmd_page(*pmd) + ((address & ~PMD_MASK) >> PAGE_SHIFT);  		if (flags & FOLL_GET)  			get_page(page);  	} else { -		if (is_hugetlb_entry_migration(huge_ptep_get((pte_t *)pmd))) { +		if (is_hugetlb_entry_migration(pte)) {  			spin_unlock(ptl);  			__migration_entry_wait(mm, (pte_t *)pmd, ptl);  			goto retry;  | 
