diff options
| -rw-r--r-- | mm/mincore.c | 75 | 
1 files changed, 58 insertions, 17 deletions
diff --git a/mm/mincore.c b/mm/mincore.c index 211604adc23..9ac42dc6d7b 100644 --- a/mm/mincore.c +++ b/mm/mincore.c @@ -144,6 +144,60 @@ static void mincore_pte_range(struct vm_area_struct *vma, pmd_t *pmd,  	pte_unmap_unlock(ptep - 1, ptl);  } +static void mincore_pmd_range(struct vm_area_struct *vma, pud_t *pud, +			unsigned long addr, unsigned long end, +			unsigned char *vec) +{ +	unsigned long next; +	pmd_t *pmd; + +	pmd = pmd_offset(pud, addr); +	do { +		next = pmd_addr_end(addr, end); +		if (pmd_none_or_clear_bad(pmd)) +			mincore_unmapped_range(vma, addr, next, vec); +		else +			mincore_pte_range(vma, pmd, addr, next, vec); +		vec += (next - addr) >> PAGE_SHIFT; +	} while (pmd++, addr = next, addr != end); +} + +static void mincore_pud_range(struct vm_area_struct *vma, pgd_t *pgd, +			unsigned long addr, unsigned long end, +			unsigned char *vec) +{ +	unsigned long next; +	pud_t *pud; + +	pud = pud_offset(pgd, addr); +	do { +		next = pud_addr_end(addr, end); +		if (pud_none_or_clear_bad(pud)) +			mincore_unmapped_range(vma, addr, next, vec); +		else +			mincore_pmd_range(vma, pud, addr, next, vec); +		vec += (next - addr) >> PAGE_SHIFT; +	} while (pud++, addr = next, addr != end); +} + +static void mincore_page_range(struct vm_area_struct *vma, +			unsigned long addr, unsigned long end, +			unsigned char *vec) +{ +	unsigned long next; +	pgd_t *pgd; + +	pgd = pgd_offset(vma->vm_mm, addr); +	do { +		next = pgd_addr_end(addr, end); +		if (pgd_none_or_clear_bad(pgd)) +			mincore_unmapped_range(vma, addr, next, vec); +		else +			mincore_pud_range(vma, pgd, addr, next, vec); +		vec += (next - addr) >> PAGE_SHIFT; +	} while (pgd++, addr = next, addr != end); +} +  /*   * Do a chunk of "sys_mincore()". We've already checked   * all the arguments, we hold the mmap semaphore: we should @@ -151,9 +205,6 @@ static void mincore_pte_range(struct vm_area_struct *vma, pmd_t *pmd,   */  static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *vec)  { -	pgd_t *pgd; -	pud_t *pud; -	pmd_t *pmd;  	struct vm_area_struct *vma;  	unsigned long end; @@ -170,21 +221,11 @@ static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *v  	end = pmd_addr_end(addr, end); -	pgd = pgd_offset(vma->vm_mm, addr); -	if (pgd_none_or_clear_bad(pgd)) -		goto none_mapped; -	pud = pud_offset(pgd, addr); -	if (pud_none_or_clear_bad(pud)) -		goto none_mapped; -	pmd = pmd_offset(pud, addr); -	if (pmd_none_or_clear_bad(pmd)) -		goto none_mapped; - -	mincore_pte_range(vma, pmd, addr, end, vec); -	return (end - addr) >> PAGE_SHIFT; +	if (is_vm_hugetlb_page(vma)) +		mincore_hugetlb_page_range(vma, addr, end, vec); +	else +		mincore_page_range(vma, addr, end, vec); -none_mapped: -	mincore_unmapped_range(vma, addr, end, vec);  	return (end - addr) >> PAGE_SHIFT;  }  |