aboutsummaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-11-19 22:02:36 -0500
committerSteven Rostedt <rostedt@goodmis.org>2013-11-19 22:02:36 -0500
commitf294dc27a052f476d216c04ab386d84eb80f3c8c (patch)
treef000092a954a409b855d6b9c49435e07267904a8 /mm
parente4b4e0ed014258359aaf089824808333d768bc79 (diff)
parent14aa272fcd1cdbe7173073250c767bc7a37278ce (diff)
Merge tag 'v3.4.69' into v3.4-rt
This is the 3.4.69 stable release Conflicts: mm/swap.c
Diffstat (limited to 'mm')
-rw-r--r--mm/swap.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/mm/swap.c b/mm/swap.c
index 15c1c53bff89..bff7beaed861 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -30,6 +30,7 @@
#include <linux/backing-dev.h>
#include <linux/memcontrol.h>
#include <linux/gfp.h>
+#include <linux/hugetlb.h>
#include <linux/locallock.h>
#include "internal.h"
@@ -72,13 +73,26 @@ static void __put_compound_page(struct page *page)
{
compound_page_dtor *dtor;
- __page_cache_release(page);
+ if (!PageHuge(page))
+ __page_cache_release(page);
dtor = get_compound_page_dtor(page);
(*dtor)(page);
}
static void put_compound_page(struct page *page)
{
+ /*
+ * hugetlbfs pages cannot be split from under us. If this is a
+ * hugetlbfs page, check refcount on head page and release the page if
+ * the refcount becomes zero.
+ */
+ if (PageHuge(page)) {
+ page = compound_head(page);
+ if (put_page_testzero(page))
+ __put_compound_page(page);
+ return;
+ }
+
if (unlikely(PageTail(page))) {
/* __split_huge_page_refcount can run under us */
struct page *page_head = compound_trans_head(page);
@@ -163,8 +177,20 @@ bool __get_page_tail(struct page *page)
*/
unsigned long flags;
bool got = false;
- struct page *page_head = compound_trans_head(page);
+ struct page *page_head;
+
+ /*
+ * If this is a hugetlbfs page it cannot be split under us. Simply
+ * increment refcount for the head page.
+ */
+ if (PageHuge(page)) {
+ page_head = compound_head(page);
+ atomic_inc(&page_head->_count);
+ got = true;
+ goto out;
+ }
+ page_head = compound_trans_head(page);
if (likely(page != page_head && get_page_unless_zero(page_head))) {
/*
* page_head wasn't a dangling pointer but it
@@ -182,6 +208,7 @@ bool __get_page_tail(struct page *page)
if (unlikely(!got))
put_page(page_head);
}
+out:
return got;
}
EXPORT_SYMBOL(__get_page_tail);