]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
thp-tail-page-refcounting-fix-6
authorAndrea Arcangeli <aarcange@redhat.com>
Wed, 28 Sep 2011 00:50:22 +0000 (10:50 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 4 Oct 2011 07:38:38 +0000 (18:38 +1100)
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Signed-off-by: Andrew Morton <>
include/linux/mm.h
mm/internal.h
mm/swap.c

index 527c5bb4188a4b2d74c547f1b05887f71acf4d7e..95426cdc396ef5c04ff80c47dde8894653c09e98 100644 (file)
@@ -377,7 +377,7 @@ static inline int page_count(struct page *page)
        return atomic_read(&compound_head(page)->_count);
 }
 
-extern int __get_page_tail(struct page *page);
+extern bool __get_page_tail(struct page *page);
 
 static inline void get_page(struct page *page)
 {
index cd09cca7042379f1f383ada467fa6fd4261060f4..2189af491783f958c1337ebf1f1bb14dc5cd8b5d 100644 (file)
@@ -59,6 +59,11 @@ static inline void __get_page_tail_foll(struct page *page,
        atomic_inc(&page->_mapcount);
 }
 
+/*
+ * This is meant to be called as the FOLL_GET operation of
+ * follow_page() and it must be called while holding the proper PT
+ * lock while the pte (or pmd_trans_huge) is still mapping the page.
+ */
 static inline void get_page_foll(struct page *page)
 {
        if (unlikely(PageTail(page)))
index 93c0b582ee06359e9ba6db034146910bbf8e2d4b..1c5576ae355229f599b4edc22de97da66be0ce9b 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -79,6 +79,7 @@ static void put_compound_page(struct page *page)
        if (unlikely(PageTail(page))) {
                /* __split_huge_page_refcount can run under us */
                struct page *page_head = compound_trans_head(page);
+
                if (likely(page != page_head &&
                           get_page_unless_zero(page_head))) {
                        unsigned long flags;
@@ -143,7 +144,11 @@ void put_page(struct page *page)
 }
 EXPORT_SYMBOL(put_page);
 
-int __get_page_tail(struct page *page)
+/*
+ * This function is exported but must not be called by anything other
+ * than get_page(). It implements the slow path of get_page().
+ */
+bool __get_page_tail(struct page *page)
 {
        /*
         * This takes care of get_page() if run on a tail page
@@ -154,8 +159,9 @@ int __get_page_tail(struct page *page)
         * split_huge_page().
         */
        unsigned long flags;
-       int got = 0;
+       bool got = false;
        struct page *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
@@ -167,7 +173,7 @@ int __get_page_tail(struct page *page)
                /* here __split_huge_page_refcount won't run anymore */
                if (likely(PageTail(page))) {
                        __get_page_tail_foll(page, false);
-                       got = 1;
+                       got = true;
                }
                compound_unlock_irqrestore(page_head, flags);
                if (unlikely(!got))