diff options
Diffstat (limited to 'mm/pagewalk.c')
| -rw-r--r-- | mm/pagewalk.c | 47 | 
1 files changed, 37 insertions, 10 deletions
diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 7b47a57b664..8b1a2ce21ee 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -80,6 +80,37 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,  	return err;  } +#ifdef CONFIG_HUGETLB_PAGE +static unsigned long hugetlb_entry_end(struct hstate *h, unsigned long addr, +				       unsigned long end) +{ +	unsigned long boundary = (addr & huge_page_mask(h)) + huge_page_size(h); +	return boundary < end ? boundary : end; +} + +static int walk_hugetlb_range(struct vm_area_struct *vma, +			      unsigned long addr, unsigned long end, +			      struct mm_walk *walk) +{ +	struct hstate *h = hstate_vma(vma); +	unsigned long next; +	unsigned long hmask = huge_page_mask(h); +	pte_t *pte; +	int err = 0; + +	do { +		next = hugetlb_entry_end(h, addr, end); +		pte = huge_pte_offset(walk->mm, addr & hmask); +		if (pte && walk->hugetlb_entry) +			err = walk->hugetlb_entry(pte, hmask, addr, next, walk); +		if (err) +			return err; +	} while (addr = next, addr != end); + +	return 0; +} +#endif +  /**   * walk_page_range - walk a memory map's page tables with a callback   * @mm: memory map to walk @@ -128,20 +159,16 @@ int walk_page_range(unsigned long addr, unsigned long end,  		vma = find_vma(walk->mm, addr);  #ifdef CONFIG_HUGETLB_PAGE  		if (vma && is_vm_hugetlb_page(vma)) { -			pte_t *pte; -			struct hstate *hs; -  			if (vma->vm_end < next)  				next = vma->vm_end; -			hs = hstate_vma(vma); -			pte = huge_pte_offset(walk->mm, -					      addr & huge_page_mask(hs)); -			if (pte && !huge_pte_none(huge_ptep_get(pte)) -			    && walk->hugetlb_entry) -				err = walk->hugetlb_entry(pte, addr, -							  next, walk); +			/* +			 * Hugepage is very tightly coupled with vma, so +			 * walk through hugetlb entries within a given vma. +			 */ +			err = walk_hugetlb_range(vma, addr, next, walk);  			if (err)  				break; +			pgd = pgd_offset(walk->mm, next);  			continue;  		}  #endif  |