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 | } |
