Merge branch 'auto' of git://git.kernel.org/pub/scm/linux/kernel/git/rric/oprofile...
[firefly-linux-kernel-4.4.55.git] / mm / page_alloc.c
index 6407cbfccd77ea0fb7399191670e152b6c0a9bff..a5f3c278c5732f4f3c8c9258f5b95b2c86b3e490 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/bootmem.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
 #include <linux/pagevec.h>
@@ -558,6 +559,8 @@ static void __free_pages_ok(struct page *page, unsigned int order)
        int bad = 0;
        int clearMlocked = PageMlocked(page);
 
+       kmemcheck_free_shadow(page, order);
+
        for (i = 0 ; i < (1 << order) ; ++i)
                bad += free_pages_check(page + i);
        if (bad)
@@ -1020,6 +1023,8 @@ static void free_hot_cold_page(struct page *page, int cold)
        unsigned long flags;
        int clearMlocked = PageMlocked(page);
 
+       kmemcheck_free_shadow(page, 0);
+
        if (PageAnon(page))
                page->mapping = NULL;
        if (free_pages_check(page))
@@ -1076,6 +1081,16 @@ void split_page(struct page *page, unsigned int order)
 
        VM_BUG_ON(PageCompound(page));
        VM_BUG_ON(!page_count(page));
+
+#ifdef CONFIG_KMEMCHECK
+       /*
+        * Split shadow pages too, because free(page[0]) would
+        * otherwise free the whole shadow.
+        */
+       if (kmemcheck_page_is_tracked(page))
+               split_page(virt_to_page(page[0].shadow), order);
+#endif
+
        for (i = 1; i < (1 << order); i++)
                set_page_refcounted(page + i);
 }
@@ -1462,15 +1477,33 @@ zonelist_scan:
                BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);
                if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
                        unsigned long mark;
+                       int ret;
+
                        mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
-                       if (!zone_watermark_ok(zone, order, mark,
-                                   classzone_idx, alloc_flags)) {
-                               if (!zone_reclaim_mode ||
-                                   !zone_reclaim(zone, gfp_mask, order))
+                       if (zone_watermark_ok(zone, order, mark,
+                                   classzone_idx, alloc_flags))
+                               goto try_this_zone;
+
+                       if (zone_reclaim_mode == 0)
+                               goto this_zone_full;
+
+                       ret = zone_reclaim(zone, gfp_mask, order);
+                       switch (ret) {
+                       case ZONE_RECLAIM_NOSCAN:
+                               /* did not scan */
+                               goto try_next_zone;
+                       case ZONE_RECLAIM_FULL:
+                               /* scanned but unreclaimable */
+                               goto this_zone_full;
+                       default:
+                               /* did we reclaim enough */
+                               if (!zone_watermark_ok(zone, order, mark,
+                                               classzone_idx, alloc_flags))
                                        goto this_zone_full;
                        }
                }
 
+try_this_zone:
                page = buffered_rmqueue(preferred_zone, zone, order,
                                                gfp_mask, migratetype);
                if (page)
@@ -1810,7 +1843,10 @@ nopage:
                dump_stack();
                show_mem();
        }
+       return page;
 got_pg:
+       if (kmemcheck_enabled)
+               kmemcheck_pagealloc_alloc(page, order, gfp_mask);
        return page;
 
 }