diff options
Diffstat (limited to 'mm/hugetlb.c')
| -rw-r--r-- | mm/hugetlb.c | 54 | 
1 files changed, 50 insertions, 4 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 421aee99b84..6058b53dcb8 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -354,11 +354,26 @@ static int vma_has_reserves(struct vm_area_struct *vma)  	return 0;  } +static void clear_gigantic_page(struct page *page, +			unsigned long addr, unsigned long sz) +{ +	int i; +	struct page *p = page; + +	might_sleep(); +	for (i = 0; i < sz/PAGE_SIZE; i++, p = mem_map_next(p, page, i)) { +		cond_resched(); +		clear_user_highpage(p, addr + i * PAGE_SIZE); +	} +}  static void clear_huge_page(struct page *page,  			unsigned long addr, unsigned long sz)  {  	int i; +	if (unlikely(sz > MAX_ORDER_NR_PAGES)) +		return clear_gigantic_page(page, addr, sz); +  	might_sleep();  	for (i = 0; i < sz/PAGE_SIZE; i++) {  		cond_resched(); @@ -366,12 +381,32 @@ static void clear_huge_page(struct page *page,  	}  } +static void copy_gigantic_page(struct page *dst, struct page *src, +			   unsigned long addr, struct vm_area_struct *vma) +{ +	int i; +	struct hstate *h = hstate_vma(vma); +	struct page *dst_base = dst; +	struct page *src_base = src; +	might_sleep(); +	for (i = 0; i < pages_per_huge_page(h); ) { +		cond_resched(); +		copy_user_highpage(dst, src, addr + i*PAGE_SIZE, vma); + +		i++; +		dst = mem_map_next(dst, dst_base, i); +		src = mem_map_next(src, src_base, i); +	} +}  static void copy_huge_page(struct page *dst, struct page *src,  			   unsigned long addr, struct vm_area_struct *vma)  {  	int i;  	struct hstate *h = hstate_vma(vma); +	if (unlikely(pages_per_huge_page(h) > MAX_ORDER_NR_PAGES)) +		return copy_gigantic_page(dst, src, addr, vma); +  	might_sleep();  	for (i = 0; i < pages_per_huge_page(h); i++) {  		cond_resched(); @@ -456,6 +491,8 @@ static void update_and_free_page(struct hstate *h, struct page *page)  {  	int i; +	VM_BUG_ON(h->order >= MAX_ORDER); +  	h->nr_huge_pages--;  	h->nr_huge_pages_node[page_to_nid(page)]--;  	for (i = 0; i < pages_per_huge_page(h); i++) { @@ -970,6 +1007,14 @@ found:  	return 1;  } +static void prep_compound_huge_page(struct page *page, int order) +{ +	if (unlikely(order > (MAX_ORDER - 1))) +		prep_compound_gigantic_page(page, order); +	else +		prep_compound_page(page, order); +} +  /* Put bootmem huge pages into the standard lists after mem_map is up */  static void __init gather_bootmem_prealloc(void)  { @@ -980,7 +1025,7 @@ static void __init gather_bootmem_prealloc(void)  		struct hstate *h = m->hstate;  		__ClearPageReserved(page);  		WARN_ON(page_count(page) != 1); -		prep_compound_page(page, h->order); +		prep_compound_huge_page(page, h->order);  		prep_new_huge_page(h, page, page_to_nid(page));  	}  } @@ -1751,6 +1796,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,  static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,  				struct page *page, unsigned long address)  { +	struct hstate *h = hstate_vma(vma);  	struct vm_area_struct *iter_vma;  	struct address_space *mapping;  	struct prio_tree_iter iter; @@ -1760,7 +1806,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,  	 * vm_pgoff is in PAGE_SIZE units, hence the different calculation  	 * from page cache lookup which is in HPAGE_SIZE units.  	 */ -	address = address & huge_page_mask(hstate_vma(vma)); +	address = address & huge_page_mask(h);  	pgoff = ((address - vma->vm_start) >> PAGE_SHIFT)  		+ (vma->vm_pgoff >> PAGE_SHIFT);  	mapping = (struct address_space *)page_private(page); @@ -1779,7 +1825,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,  		 */  		if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER))  			unmap_hugepage_range(iter_vma, -				address, address + HPAGE_SIZE, +				address, address + huge_page_size(h),  				page);  	} @@ -2130,7 +2176,7 @@ same_page:  			if (zeropage_ok)  				pages[i] = ZERO_PAGE(0);  			else -				pages[i] = page + pfn_offset; +				pages[i] = mem_map_offset(page, pfn_offset);  			get_page(pages[i]);  		}  |