hugetlb: debit quota in alloc_huge_page
Now that quota is credited by free_huge_page(), calls to hugetlb_get_quota() seem out of place. The alloc/free API is unbalanced because we handle the hugetlb_put_quota() but expect the caller to open-code hugetlb_get_quota(). Move the get inside alloc_huge_page to clean up this disparity. This patch has been kept apart from the previous patch because of the somewhat dodgy ERR_PTR() use herein. Moving the quota logic means that alloc_huge_page() has two failure modes. Quota failure must result in a SIGBUS while a standard allocation failure is OOM. Unfortunately, ERR_PTR() doesn't like the small positive errnos we have in VM_FAULT_* so they must be negated before they are used. Does anyone take issue with the way I am using PTR_ERR. If so, what are your thoughts on how to clean this up (without needing an if,else if,else block at each alloc_huge_page() callsite)? Signed-off-by: Adam Litke <agl@us.ibm.com> Cc: Ken Chen <kenchen@google.com> Cc: Andy Whitcroft <apw@shadowen.org> Cc: Dave Hansen <haveblue@us.ibm.com> Cc: David Gibson <hermes@gibson.dropbear.id.au> Cc: William Lee Irwin III <wli@holomorphy.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
c79fb75e5a
commit
2fc39cec6a
1 changed files with 12 additions and 12 deletions
24
mm/hugetlb.c
24
mm/hugetlb.c
|
@ -388,6 +388,10 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
|
||||||
unsigned long addr)
|
unsigned long addr)
|
||||||
{
|
{
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
struct address_space *mapping = vma->vm_file->f_mapping;
|
||||||
|
|
||||||
|
if (hugetlb_get_quota(mapping))
|
||||||
|
return ERR_PTR(-VM_FAULT_SIGBUS);
|
||||||
|
|
||||||
if (vma->vm_flags & VM_MAYSHARE)
|
if (vma->vm_flags & VM_MAYSHARE)
|
||||||
page = alloc_huge_page_shared(vma, addr);
|
page = alloc_huge_page_shared(vma, addr);
|
||||||
|
@ -395,9 +399,10 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
|
||||||
page = alloc_huge_page_private(vma, addr);
|
page = alloc_huge_page_private(vma, addr);
|
||||||
if (page) {
|
if (page) {
|
||||||
set_page_refcounted(page);
|
set_page_refcounted(page);
|
||||||
set_page_private(page, (unsigned long) vma->vm_file->f_mapping);
|
set_page_private(page, (unsigned long) mapping);
|
||||||
}
|
return page;
|
||||||
return page;
|
} else
|
||||||
|
return ERR_PTR(-VM_FAULT_OOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init hugetlb_init(void)
|
static int __init hugetlb_init(void)
|
||||||
|
@ -737,15 +742,13 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
set_huge_ptep_writable(vma, address, ptep);
|
set_huge_ptep_writable(vma, address, ptep);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (hugetlb_get_quota(vma->vm_file->f_mapping))
|
|
||||||
return VM_FAULT_SIGBUS;
|
|
||||||
|
|
||||||
page_cache_get(old_page);
|
page_cache_get(old_page);
|
||||||
new_page = alloc_huge_page(vma, address);
|
new_page = alloc_huge_page(vma, address);
|
||||||
|
|
||||||
if (!new_page) {
|
if (IS_ERR(new_page)) {
|
||||||
page_cache_release(old_page);
|
page_cache_release(old_page);
|
||||||
return VM_FAULT_OOM;
|
return -PTR_ERR(new_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&mm->page_table_lock);
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
@ -789,12 +792,9 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||||
size = i_size_read(mapping->host) >> HPAGE_SHIFT;
|
size = i_size_read(mapping->host) >> HPAGE_SHIFT;
|
||||||
if (idx >= size)
|
if (idx >= size)
|
||||||
goto out;
|
goto out;
|
||||||
if (hugetlb_get_quota(mapping))
|
|
||||||
goto out;
|
|
||||||
page = alloc_huge_page(vma, address);
|
page = alloc_huge_page(vma, address);
|
||||||
if (!page) {
|
if (IS_ERR(page)) {
|
||||||
hugetlb_put_quota(mapping);
|
ret = -PTR_ERR(page);
|
||||||
ret = VM_FAULT_OOM;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
clear_huge_page(page, address);
|
clear_huge_page(page, address);
|
||||||
|
|
Loading…
Reference in a new issue