mm: clear pmd_numa before invalidating
[firefly-linux-kernel-4.4.55.git] / mm / swap.c
index dfd7d71d68418023b592c09a7d18c7a3ac4c5843..9f2225f2b5b0f777acf767427a867ff8ab595c38 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -31,6 +31,7 @@
 #include <linux/memcontrol.h>
 #include <linux/gfp.h>
 #include <linux/uio.h>
+#include <linux/hugetlb.h>
 
 #include "internal.h"
 
@@ -78,6 +79,19 @@ static void __put_compound_page(struct page *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);
@@ -181,38 +195,51 @@ bool __get_page_tail(struct page *page)
         * proper PT lock that already serializes against
         * split_huge_page().
         */
-       unsigned long flags;
        bool got = false;
-       struct page *page_head = compound_trans_head(page);
+       struct page *page_head;
 
-       if (likely(page != page_head && get_page_unless_zero(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;
+       } else {
+               unsigned long flags;
+
+               page_head = compound_trans_head(page);
+               if (likely(page != page_head &&
+                                       get_page_unless_zero(page_head))) {
+
+                       /* Ref to put_compound_page() comment. */
+                       if (PageSlab(page_head)) {
+                               if (likely(PageTail(page))) {
+                                       __get_page_tail_foll(page, false);
+                                       return true;
+                               } else {
+                                       put_page(page_head);
+                                       return false;
+                               }
+                       }
 
-               /* Ref to put_compound_page() comment. */
-               if (PageSlab(page_head)) {
+                       /*
+                        * page_head wasn't a dangling pointer but it
+                        * may not be a head page anymore by the time
+                        * we obtain the lock. That is ok as long as it
+                        * can't be freed from under us.
+                        */
+                       flags = compound_lock_irqsave(page_head);
+                       /* here __split_huge_page_refcount won't run anymore */
                        if (likely(PageTail(page))) {
                                __get_page_tail_foll(page, false);
-                               return true;
-                       } else {
-                               put_page(page_head);
-                               return false;
+                               got = true;
                        }
+                       compound_unlock_irqrestore(page_head, flags);
+                       if (unlikely(!got))
+                               put_page(page_head);
                }
-
-               /*
-                * page_head wasn't a dangling pointer but it
-                * may not be a head page anymore by the time
-                * we obtain the lock. That is ok as long as it
-                * can't be freed from under us.
-                */
-               flags = compound_lock_irqsave(page_head);
-               /* here __split_huge_page_refcount won't run anymore */
-               if (likely(PageTail(page))) {
-                       __get_page_tail_foll(page, false);
-                       got = true;
-               }
-               compound_unlock_irqrestore(page_head, flags);
-               if (unlikely(!got))
-                       put_page(page_head);
        }
        return got;
 }