diff options
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r-- | mm/hugetlb.c | 95 |
1 files changed, 62 insertions, 33 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 8b809ecefa39..6121b57bbe96 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -116,7 +116,9 @@ static void update_and_free_page(struct page *page) | |||
116 | static void free_huge_page(struct page *page) | 116 | static void free_huge_page(struct page *page) |
117 | { | 117 | { |
118 | int nid = page_to_nid(page); | 118 | int nid = page_to_nid(page); |
119 | struct address_space *mapping; | ||
119 | 120 | ||
121 | mapping = (struct address_space *) page_private(page); | ||
120 | BUG_ON(page_count(page)); | 122 | BUG_ON(page_count(page)); |
121 | INIT_LIST_HEAD(&page->lru); | 123 | INIT_LIST_HEAD(&page->lru); |
122 | 124 | ||
@@ -129,6 +131,9 @@ static void free_huge_page(struct page *page) | |||
129 | enqueue_huge_page(page); | 131 | enqueue_huge_page(page); |
130 | } | 132 | } |
131 | spin_unlock(&hugetlb_lock); | 133 | spin_unlock(&hugetlb_lock); |
134 | if (mapping) | ||
135 | hugetlb_put_quota(mapping, 1); | ||
136 | set_page_private(page, 0); | ||
132 | } | 137 | } |
133 | 138 | ||
134 | /* | 139 | /* |
@@ -323,7 +328,7 @@ free: | |||
323 | * allocated to satisfy the reservation must be explicitly freed if they were | 328 | * allocated to satisfy the reservation must be explicitly freed if they were |
324 | * never used. | 329 | * never used. |
325 | */ | 330 | */ |
326 | void return_unused_surplus_pages(unsigned long unused_resv_pages) | 331 | static void return_unused_surplus_pages(unsigned long unused_resv_pages) |
327 | { | 332 | { |
328 | static int nid = -1; | 333 | static int nid = -1; |
329 | struct page *page; | 334 | struct page *page; |
@@ -353,35 +358,50 @@ void return_unused_surplus_pages(unsigned long unused_resv_pages) | |||
353 | } | 358 | } |
354 | } | 359 | } |
355 | 360 | ||
356 | static struct page *alloc_huge_page(struct vm_area_struct *vma, | 361 | |
357 | unsigned long addr) | 362 | static struct page *alloc_huge_page_shared(struct vm_area_struct *vma, |
363 | unsigned long addr) | ||
358 | { | 364 | { |
359 | struct page *page = NULL; | 365 | struct page *page; |
360 | int use_reserved_page = vma->vm_flags & VM_MAYSHARE; | ||
361 | 366 | ||
362 | spin_lock(&hugetlb_lock); | 367 | spin_lock(&hugetlb_lock); |
363 | if (!use_reserved_page && (free_huge_pages <= resv_huge_pages)) | ||
364 | goto fail; | ||
365 | |||
366 | page = dequeue_huge_page(vma, addr); | 368 | page = dequeue_huge_page(vma, addr); |
367 | if (!page) | ||
368 | goto fail; | ||
369 | |||
370 | spin_unlock(&hugetlb_lock); | 369 | spin_unlock(&hugetlb_lock); |
371 | set_page_refcounted(page); | 370 | return page ? page : ERR_PTR(-VM_FAULT_OOM); |
372 | return page; | 371 | } |
373 | 372 | ||
374 | fail: | 373 | static struct page *alloc_huge_page_private(struct vm_area_struct *vma, |
375 | spin_unlock(&hugetlb_lock); | 374 | unsigned long addr) |
375 | { | ||
376 | struct page *page = NULL; | ||
376 | 377 | ||
377 | /* | 378 | if (hugetlb_get_quota(vma->vm_file->f_mapping, 1)) |
378 | * Private mappings do not use reserved huge pages so the allocation | 379 | return ERR_PTR(-VM_FAULT_SIGBUS); |
379 | * may have failed due to an undersized hugetlb pool. Try to grab a | 380 | |
380 | * surplus huge page from the buddy allocator. | 381 | spin_lock(&hugetlb_lock); |
381 | */ | 382 | if (free_huge_pages > resv_huge_pages) |
382 | if (!use_reserved_page) | 383 | page = dequeue_huge_page(vma, addr); |
384 | spin_unlock(&hugetlb_lock); | ||
385 | if (!page) | ||
383 | page = alloc_buddy_huge_page(vma, addr); | 386 | page = alloc_buddy_huge_page(vma, addr); |
387 | return page ? page : ERR_PTR(-VM_FAULT_OOM); | ||
388 | } | ||
389 | |||
390 | static struct page *alloc_huge_page(struct vm_area_struct *vma, | ||
391 | unsigned long addr) | ||
392 | { | ||
393 | struct page *page; | ||
394 | struct address_space *mapping = vma->vm_file->f_mapping; | ||
384 | 395 | ||
396 | if (vma->vm_flags & VM_MAYSHARE) | ||
397 | page = alloc_huge_page_shared(vma, addr); | ||
398 | else | ||
399 | page = alloc_huge_page_private(vma, addr); | ||
400 | |||
401 | if (!IS_ERR(page)) { | ||
402 | set_page_refcounted(page); | ||
403 | set_page_private(page, (unsigned long) mapping); | ||
404 | } | ||
385 | return page; | 405 | return page; |
386 | } | 406 | } |
387 | 407 | ||
@@ -726,9 +746,9 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, | |||
726 | page_cache_get(old_page); | 746 | page_cache_get(old_page); |
727 | new_page = alloc_huge_page(vma, address); | 747 | new_page = alloc_huge_page(vma, address); |
728 | 748 | ||
729 | if (!new_page) { | 749 | if (IS_ERR(new_page)) { |
730 | page_cache_release(old_page); | 750 | page_cache_release(old_page); |
731 | return VM_FAULT_OOM; | 751 | return -PTR_ERR(new_page); |
732 | } | 752 | } |
733 | 753 | ||
734 | spin_unlock(&mm->page_table_lock); | 754 | spin_unlock(&mm->page_table_lock); |
@@ -772,27 +792,28 @@ retry: | |||
772 | size = i_size_read(mapping->host) >> HPAGE_SHIFT; | 792 | size = i_size_read(mapping->host) >> HPAGE_SHIFT; |
773 | if (idx >= size) | 793 | if (idx >= size) |
774 | goto out; | 794 | goto out; |
775 | if (hugetlb_get_quota(mapping)) | ||
776 | goto out; | ||
777 | page = alloc_huge_page(vma, address); | 795 | page = alloc_huge_page(vma, address); |
778 | if (!page) { | 796 | if (IS_ERR(page)) { |
779 | hugetlb_put_quota(mapping); | 797 | ret = -PTR_ERR(page); |
780 | ret = VM_FAULT_OOM; | ||
781 | goto out; | 798 | goto out; |
782 | } | 799 | } |
783 | clear_huge_page(page, address); | 800 | clear_huge_page(page, address); |
784 | 801 | ||
785 | if (vma->vm_flags & VM_SHARED) { | 802 | if (vma->vm_flags & VM_SHARED) { |
786 | int err; | 803 | int err; |
804 | struct inode *inode = mapping->host; | ||
787 | 805 | ||
788 | err = add_to_page_cache(page, mapping, idx, GFP_KERNEL); | 806 | err = add_to_page_cache(page, mapping, idx, GFP_KERNEL); |
789 | if (err) { | 807 | if (err) { |
790 | put_page(page); | 808 | put_page(page); |
791 | hugetlb_put_quota(mapping); | ||
792 | if (err == -EEXIST) | 809 | if (err == -EEXIST) |
793 | goto retry; | 810 | goto retry; |
794 | goto out; | 811 | goto out; |
795 | } | 812 | } |
813 | |||
814 | spin_lock(&inode->i_lock); | ||
815 | inode->i_blocks += BLOCKS_PER_HUGEPAGE; | ||
816 | spin_unlock(&inode->i_lock); | ||
796 | } else | 817 | } else |
797 | lock_page(page); | 818 | lock_page(page); |
798 | } | 819 | } |
@@ -822,7 +843,6 @@ out: | |||
822 | 843 | ||
823 | backout: | 844 | backout: |
824 | spin_unlock(&mm->page_table_lock); | 845 | spin_unlock(&mm->page_table_lock); |
825 | hugetlb_put_quota(mapping); | ||
826 | unlock_page(page); | 846 | unlock_page(page); |
827 | put_page(page); | 847 | put_page(page); |
828 | goto out; | 848 | goto out; |
@@ -868,7 +888,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, | |||
868 | 888 | ||
869 | int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | 889 | int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, |
870 | struct page **pages, struct vm_area_struct **vmas, | 890 | struct page **pages, struct vm_area_struct **vmas, |
871 | unsigned long *position, int *length, int i) | 891 | unsigned long *position, int *length, int i, |
892 | int write) | ||
872 | { | 893 | { |
873 | unsigned long pfn_offset; | 894 | unsigned long pfn_offset; |
874 | unsigned long vaddr = *position; | 895 | unsigned long vaddr = *position; |
@@ -890,7 +911,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
890 | int ret; | 911 | int ret; |
891 | 912 | ||
892 | spin_unlock(&mm->page_table_lock); | 913 | spin_unlock(&mm->page_table_lock); |
893 | ret = hugetlb_fault(mm, vma, vaddr, 0); | 914 | ret = hugetlb_fault(mm, vma, vaddr, write); |
894 | spin_lock(&mm->page_table_lock); | 915 | spin_lock(&mm->page_table_lock); |
895 | if (!(ret & VM_FAULT_ERROR)) | 916 | if (!(ret & VM_FAULT_ERROR)) |
896 | continue; | 917 | continue; |
@@ -1132,6 +1153,8 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to) | |||
1132 | if (chg < 0) | 1153 | if (chg < 0) |
1133 | return chg; | 1154 | return chg; |
1134 | 1155 | ||
1156 | if (hugetlb_get_quota(inode->i_mapping, chg)) | ||
1157 | return -ENOSPC; | ||
1135 | ret = hugetlb_acct_memory(chg); | 1158 | ret = hugetlb_acct_memory(chg); |
1136 | if (ret < 0) | 1159 | if (ret < 0) |
1137 | return ret; | 1160 | return ret; |
@@ -1142,5 +1165,11 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to) | |||
1142 | void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) | 1165 | void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) |
1143 | { | 1166 | { |
1144 | long chg = region_truncate(&inode->i_mapping->private_list, offset); | 1167 | long chg = region_truncate(&inode->i_mapping->private_list, offset); |
1145 | hugetlb_acct_memory(freed - chg); | 1168 | |
1169 | spin_lock(&inode->i_lock); | ||
1170 | inode->i_blocks -= BLOCKS_PER_HUGEPAGE * freed; | ||
1171 | spin_unlock(&inode->i_lock); | ||
1172 | |||
1173 | hugetlb_put_quota(inode->i_mapping, (chg - freed)); | ||
1174 | hugetlb_acct_memory(-(chg - freed)); | ||
1146 | } | 1175 | } |