diff options
Diffstat (limited to 'mm/hugetlb.c')
| -rw-r--r-- | mm/hugetlb.c | 44 | 
1 files changed, 29 insertions, 15 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 38633864a93..ce8cbb29860 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -262,7 +262,7 @@ struct resv_map {  	struct list_head regions;  }; -struct resv_map *resv_map_alloc(void) +static struct resv_map *resv_map_alloc(void)  {  	struct resv_map *resv_map = kmalloc(sizeof(*resv_map), GFP_KERNEL);  	if (!resv_map) @@ -274,7 +274,7 @@ struct resv_map *resv_map_alloc(void)  	return resv_map;  } -void resv_map_release(struct kref *ref) +static void resv_map_release(struct kref *ref)  {  	struct resv_map *resv_map = container_of(ref, struct resv_map, refs); @@ -289,7 +289,7 @@ static struct resv_map *vma_resv_map(struct vm_area_struct *vma)  	if (!(vma->vm_flags & VM_SHARED))  		return (struct resv_map *)(get_vma_private_data(vma) &  							~HPAGE_RESV_MASK); -	return 0; +	return NULL;  }  static void set_vma_resv_map(struct vm_area_struct *vma, struct resv_map *map) @@ -1459,11 +1459,11 @@ int hugetlb_report_meminfo(char *buf)  {  	struct hstate *h = &default_hstate;  	return sprintf(buf, -			"HugePages_Total: %5lu\n" -			"HugePages_Free:  %5lu\n" -			"HugePages_Rsvd:  %5lu\n" -			"HugePages_Surp:  %5lu\n" -			"Hugepagesize:    %5lu kB\n", +			"HugePages_Total:   %5lu\n" +			"HugePages_Free:    %5lu\n" +			"HugePages_Rsvd:    %5lu\n" +			"HugePages_Surp:    %5lu\n" +			"Hugepagesize:   %8lu kB\n",  			h->nr_huge_pages,  			h->free_huge_pages,  			h->resv_huge_pages, @@ -1747,10 +1747,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,   * from other VMAs and let the children be SIGKILLed if they are faulting the   * same region.   */ -int unmap_ref_private(struct mm_struct *mm, -					struct vm_area_struct *vma, -					struct page *page, -					unsigned long address) +static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma, +				struct page *page, unsigned long address)  {  	struct vm_area_struct *iter_vma;  	struct address_space *mapping; @@ -2073,6 +2071,14 @@ follow_huge_pud(struct mm_struct *mm, unsigned long address,  	return NULL;  } +static int huge_zeropage_ok(pte_t *ptep, int write, int shared) +{ +	if (!ptep || write || shared) +		return 0; +	else +		return huge_pte_none(huge_ptep_get(ptep)); +} +  int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,  			struct page **pages, struct vm_area_struct **vmas,  			unsigned long *position, int *length, int i, @@ -2082,6 +2088,8 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,  	unsigned long vaddr = *position;  	int remainder = *length;  	struct hstate *h = hstate_vma(vma); +	int zeropage_ok = 0; +	int shared = vma->vm_flags & VM_SHARED;  	spin_lock(&mm->page_table_lock);  	while (vaddr < vma->vm_end && remainder) { @@ -2094,8 +2102,11 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,  		 * first, for the page indexing below to work.  		 */  		pte = huge_pte_offset(mm, vaddr & huge_page_mask(h)); +		if (huge_zeropage_ok(pte, write, shared)) +			zeropage_ok = 1; -		if (!pte || huge_pte_none(huge_ptep_get(pte)) || +		if (!pte || +		    (huge_pte_none(huge_ptep_get(pte)) && !zeropage_ok) ||  		    (write && !pte_write(huge_ptep_get(pte)))) {  			int ret; @@ -2115,8 +2126,11 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,  		page = pte_page(huge_ptep_get(pte));  same_page:  		if (pages) { -			get_page(page); -			pages[i] = page + pfn_offset; +			if (zeropage_ok) +				pages[i] = ZERO_PAGE(0); +			else +				pages[i] = page + pfn_offset; +			get_page(pages[i]);  		}  		if (vmas)  |