summaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/hugetlb.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 1e317465ecd..b52b6ddd6c1 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -367,7 +367,7 @@ static struct page *alloc_huge_page_shared(struct vm_area_struct *vma,
spin_lock(&hugetlb_lock);
page = dequeue_huge_page(vma, addr);
spin_unlock(&hugetlb_lock);
- return page;
+ return page ? page : ERR_PTR(-VM_FAULT_OOM);
}
static struct page *alloc_huge_page_private(struct vm_area_struct *vma,
@@ -375,13 +375,16 @@ static struct page *alloc_huge_page_private(struct vm_area_struct *vma,
{
struct page *page = NULL;
+ if (hugetlb_get_quota(vma->vm_file->f_mapping, 1))
+ return ERR_PTR(-VM_FAULT_SIGBUS);
+
spin_lock(&hugetlb_lock);
if (free_huge_pages > resv_huge_pages)
page = dequeue_huge_page(vma, addr);
spin_unlock(&hugetlb_lock);
if (!page)
page = alloc_buddy_huge_page(vma, addr);
- return page;
+ return page ? page : ERR_PTR(-VM_FAULT_OOM);
}
static struct page *alloc_huge_page(struct vm_area_struct *vma,
@@ -390,19 +393,16 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
struct page *page;
struct address_space *mapping = vma->vm_file->f_mapping;
- if (hugetlb_get_quota(mapping, 1))
- return ERR_PTR(-VM_FAULT_SIGBUS);
-
if (vma->vm_flags & VM_MAYSHARE)
page = alloc_huge_page_shared(vma, addr);
else
page = alloc_huge_page_private(vma, addr);
- if (page) {
+
+ if (!IS_ERR(page)) {
set_page_refcounted(page);
set_page_private(page, (unsigned long) mapping);
- return page;
- } else
- return ERR_PTR(-VM_FAULT_OOM);
+ }
+ return page;
}
static int __init hugetlb_init(void)
@@ -1148,6 +1148,8 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to)
if (chg < 0)
return chg;
+ if (hugetlb_get_quota(inode->i_mapping, chg))
+ return -ENOSPC;
ret = hugetlb_acct_memory(chg);
if (ret < 0)
return ret;
@@ -1158,5 +1160,6 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to)
void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
{
long chg = region_truncate(&inode->i_mapping->private_list, offset);
- hugetlb_acct_memory(freed - chg);
+ hugetlb_put_quota(inode->i_mapping, (chg - freed));
+ hugetlb_acct_memory(-(chg - freed));
}