aboutsummaryrefslogtreecommitdiff
path: root/mm/hugetlb.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r--mm/hugetlb.c63
1 files changed, 46 insertions, 17 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index bb0b7c12801..2114fb2615e 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -21,6 +21,7 @@
#include <linux/rmap.h>
#include <linux/swap.h>
#include <linux/swapops.h>
+#include <trace/hugetlb.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -53,6 +54,14 @@ static unsigned long __initdata default_hstate_size;
*/
static DEFINE_SPINLOCK(hugetlb_lock);
+DEFINE_TRACE(hugetlb_page_release);
+DEFINE_TRACE(hugetlb_page_grab);
+DEFINE_TRACE(hugetlb_buddy_pgalloc);
+DEFINE_TRACE(hugetlb_page_alloc);
+DEFINE_TRACE(hugetlb_page_free);
+DEFINE_TRACE(hugetlb_pages_reserve);
+DEFINE_TRACE(hugetlb_pages_unreserve);
+
/*
* Region tracking -- allows tracking of reservations and instantiated pages
* across the pages in a mapping.
@@ -500,6 +509,7 @@ static void update_and_free_page(struct hstate *h, struct page *page)
VM_BUG_ON(h->order >= MAX_ORDER);
+ trace_hugetlb_page_release(page);
h->nr_huge_pages--;
h->nr_huge_pages_node[page_to_nid(page)]--;
for (i = 0; i < pages_per_huge_page(h); i++) {
@@ -534,6 +544,7 @@ static void free_huge_page(struct page *page)
int nid = page_to_nid(page);
struct address_space *mapping;
+ trace_hugetlb_page_free(page);
mapping = (struct address_space *) page_private(page);
set_page_private(page, 0);
page->mapping = NULL;
@@ -598,8 +609,10 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
{
struct page *page;
- if (h->order >= MAX_ORDER)
- return NULL;
+ if (h->order >= MAX_ORDER) {
+ page = NULL;
+ goto end;
+ }
page = alloc_pages_exact_node(nid,
htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|
@@ -608,11 +621,13 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
if (page) {
if (arch_prepare_hugepage(page)) {
__free_pages(page, huge_page_order(h));
- return NULL;
+ page = NULL;
+ goto end;
}
prep_new_huge_page(h, page, nid);
}
-
+end:
+ trace_hugetlb_page_grab(page);
return page;
}
@@ -781,7 +796,8 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
spin_lock(&hugetlb_lock);
if (h->surplus_huge_pages >= h->nr_overcommit_huge_pages) {
spin_unlock(&hugetlb_lock);
- return NULL;
+ page = NULL;
+ goto end;
} else {
h->nr_huge_pages++;
h->surplus_huge_pages++;
@@ -818,7 +834,8 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
__count_vm_event(HTLB_BUDDY_PGALLOC_FAIL);
}
spin_unlock(&hugetlb_lock);
-
+end:
+ trace_hugetlb_buddy_pgalloc(page);
return page;
}
@@ -1054,6 +1071,7 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
vma_commit_reservation(h, vma, addr);
+ trace_hugetlb_page_alloc(page);
return page;
}
@@ -2837,7 +2855,8 @@ int hugetlb_reserve_pages(struct inode *inode,
struct vm_area_struct *vma,
int acctflag)
{
- long ret, chg;
+ int ret = 0;
+ long chg;
struct hstate *h = hstate_inode(inode);
/*
@@ -2846,7 +2865,7 @@ int hugetlb_reserve_pages(struct inode *inode,
* and filesystem quota without using reserves
*/
if (acctflag & VM_NORESERVE)
- return 0;
+ goto end;
/*
* Shared mappings base their reservation on the number of pages that
@@ -2858,8 +2877,10 @@ int hugetlb_reserve_pages(struct inode *inode,
chg = region_chg(&inode->i_mapping->private_list, from, to);
else {
struct resv_map *resv_map = resv_map_alloc();
- if (!resv_map)
- return -ENOMEM;
+ if (!resv_map) {
+ ret = -ENOMEM;
+ goto end;
+ }
chg = to - from;
@@ -2867,12 +2888,16 @@ int hugetlb_reserve_pages(struct inode *inode,
set_vma_resv_flags(vma, HPAGE_RESV_OWNER);
}
- if (chg < 0)
- return chg;
+ if (chg < 0) {
+ ret = chg;
+ goto end;
+ }
/* There must be enough filesystem quota for the mapping */
- if (hugetlb_get_quota(inode->i_mapping, chg))
- return -ENOSPC;
+ if (hugetlb_get_quota(inode->i_mapping, chg)) {
+ ret = -ENOSPC;
+ goto end;
+ }
/*
* Check enough hugepages are available for the reservation.
@@ -2881,7 +2906,7 @@ int hugetlb_reserve_pages(struct inode *inode,
ret = hugetlb_acct_memory(h, chg);
if (ret < 0) {
hugetlb_put_quota(inode->i_mapping, chg);
- return ret;
+ goto end;
}
/*
@@ -2897,14 +2922,18 @@ int hugetlb_reserve_pages(struct inode *inode,
*/
if (!vma || vma->vm_flags & VM_MAYSHARE)
region_add(&inode->i_mapping->private_list, from, to);
- return 0;
+end:
+ trace_hugetlb_pages_reserve(inode, from, to, ret);
+ return ret;
}
void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
{
struct hstate *h = hstate_inode(inode);
- long chg = region_truncate(&inode->i_mapping->private_list, offset);
+ long chg;
+ trace_hugetlb_pages_unreserve(inode, offset, freed);
+ chg = region_truncate(&inode->i_mapping->private_list, offset);
spin_lock(&inode->i_lock);
inode->i_blocks -= (blocks_per_huge_page(h) * freed);
spin_unlock(&inode->i_lock);