mm/cma_debug: fix debugging alloc/free interface
[pandora-kernel.git] / mm / page_alloc.c
index 0f770cc..ef19f22 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/interrupt.h>
+#include <linux/rwsem.h>
 #include <linux/pagemap.h>
 #include <linux/jiffies.h>
 #include <linux/bootmem.h>
@@ -61,6 +62,7 @@
 #include <linux/hugetlb.h>
 #include <linux/sched/rt.h>
 #include <linux/page_owner.h>
+#include <linux/kthread.h>
 
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
@@ -242,11 +244,9 @@ static inline void reset_deferred_meminit(pg_data_t *pgdat)
 }
 
 /* Returns true if the struct page for the pfn is uninitialised */
-static inline bool __defermem_init early_page_uninitialised(unsigned long pfn)
+static inline bool __meminit early_page_uninitialised(unsigned long pfn)
 {
-       int nid = early_pfn_to_nid(pfn);
-
-       if (pfn >= NODE_DATA(nid)->first_deferred_pfn)
+       if (pfn >= NODE_DATA(early_pfn_to_nid(pfn))->first_deferred_pfn)
                return true;
 
        return false;
@@ -838,33 +838,11 @@ static int free_tail_pages_check(struct page *head_page, struct page *page)
 static void __meminit __init_single_page(struct page *page, unsigned long pfn,
                                unsigned long zone, int nid)
 {
-       struct zone *z = &NODE_DATA(nid)->node_zones[zone];
-
        set_page_links(page, zone, nid, pfn);
-       mminit_verify_page_links(page, zone, nid, pfn);
        init_page_count(page);
        page_mapcount_reset(page);
        page_cpupid_reset_last(page);
 
-       /*
-        * Mark the block movable so that blocks are reserved for
-        * movable at startup. This will force kernel allocations
-        * to reserve their blocks rather than leaking throughout
-        * the address space during boot when many long-lived
-        * kernel allocations are made. Later some blocks near
-        * the start are marked MIGRATE_RESERVE by
-        * setup_zone_migrate_reserve()
-        *
-        * bitmap is created for zone's valid pfn range. but memmap
-        * can be created for invalid pages (for alignment)
-        * check here not to call set_pageblock_migratetype() against
-        * pfn out of zone.
-        */
-       if ((z->zone_start_pfn <= pfn)
-           && (pfn < zone_end_pfn(z))
-           && !(pfn & (pageblock_nr_pages - 1)))
-               set_pageblock_migratetype(page, MIGRATE_MOVABLE);
-
        INIT_LIST_HEAD(&page->lru);
 #ifdef WANT_PAGE_VIRTUAL
        /* The shift won't overflow because ZONE_NORMAL is below 4G. */
@@ -980,7 +958,7 @@ static void __free_pages_ok(struct page *page, unsigned int order)
        local_irq_restore(flags);
 }
 
-static void __defer_init __free_pages_boot_core(struct page *page,
+static void __init __free_pages_boot_core(struct page *page,
                                        unsigned long pfn, unsigned int order)
 {
        unsigned int nr_pages = 1 << order;
@@ -1053,7 +1031,7 @@ static inline bool __meminit meminit_pfn_in_nid(unsigned long pfn, int node,
 #endif
 
 
-void __defer_init __free_pages_bootmem(struct page *page, unsigned long pfn,
+void __init __free_pages_bootmem(struct page *page, unsigned long pfn,
                                                        unsigned int order)
 {
        if (early_page_uninitialised(pfn))
@@ -1062,20 +1040,50 @@ void __defer_init __free_pages_bootmem(struct page *page, unsigned long pfn,
 }
 
 #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
+static void __init deferred_free_range(struct page *page,
+                                       unsigned long pfn, int nr_pages)
+{
+       int i;
+
+       if (!page)
+               return;
+
+       /* Free a large naturally-aligned chunk if possible */
+       if (nr_pages == MAX_ORDER_NR_PAGES &&
+           (pfn & (MAX_ORDER_NR_PAGES-1)) == 0) {
+               set_pageblock_migratetype(page, MIGRATE_MOVABLE);
+               __free_pages_boot_core(page, pfn, MAX_ORDER-1);
+               return;
+       }
+
+       for (i = 0; i < nr_pages; i++, page++, pfn++)
+               __free_pages_boot_core(page, pfn, 0);
+}
+
+static __initdata DECLARE_RWSEM(pgdat_init_rwsem);
+
 /* Initialise remaining memory on a node */
-void __defermem_init deferred_init_memmap(int nid)
+static int __init deferred_init_memmap(void *data)
 {
+       pg_data_t *pgdat = data;
+       int nid = pgdat->node_id;
        struct mminit_pfnnid_cache nid_init_state = { };
        unsigned long start = jiffies;
        unsigned long nr_pages = 0;
        unsigned long walk_start, walk_end;
        int i, zid;
        struct zone *zone;
-       pg_data_t *pgdat = NODE_DATA(nid);
        unsigned long first_init_pfn = pgdat->first_deferred_pfn;
+       const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
 
-       if (first_init_pfn == ULONG_MAX)
-               return;
+       if (first_init_pfn == ULONG_MAX) {
+               up_read(&pgdat_init_rwsem);
+               return 0;
+       }
+
+       /* Bind memory initialisation thread to a local node if possible */
+       if (!cpumask_empty(cpumask))
+               set_cpus_allowed_ptr(current, cpumask);
 
        /* Sanity check boundaries */
        BUG_ON(pgdat->first_deferred_pfn < pgdat->node_start_pfn);
@@ -1092,6 +1100,9 @@ void __defermem_init deferred_init_memmap(int nid)
        for_each_mem_pfn_range(i, nid, &walk_start, &walk_end, NULL) {
                unsigned long pfn, end_pfn;
                struct page *page = NULL;
+               struct page *free_base_page = NULL;
+               unsigned long free_base_pfn = 0;
+               int nr_to_free = 0;
 
                end_pfn = min(walk_end, zone_end_pfn(zone));
                pfn = first_init_pfn;
@@ -1102,7 +1113,7 @@ void __defermem_init deferred_init_memmap(int nid)
 
                for (; pfn < end_pfn; pfn++) {
                        if (!pfn_valid_within(pfn))
-                               continue;
+                               goto free_range;
 
                        /*
                         * Ensure pfn_valid is checked every
@@ -1111,40 +1122,77 @@ void __defermem_init deferred_init_memmap(int nid)
                        if ((pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) {
                                if (!pfn_valid(pfn)) {
                                        page = NULL;
-                                       continue;
+                                       goto free_range;
                                }
                        }
 
                        if (!meminit_pfn_in_nid(pfn, nid, &nid_init_state)) {
                                page = NULL;
-                               continue;
+                               goto free_range;
                        }
 
                        /* Minimise pfn page lookups and scheduler checks */
                        if (page && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0) {
                                page++;
                        } else {
+                               nr_pages += nr_to_free;
+                               deferred_free_range(free_base_page,
+                                               free_base_pfn, nr_to_free);
+                               free_base_page = NULL;
+                               free_base_pfn = nr_to_free = 0;
+
                                page = pfn_to_page(pfn);
                                cond_resched();
                        }
 
                        if (page->flags) {
                                VM_BUG_ON(page_zone(page) != zone);
-                               continue;
+                               goto free_range;
                        }
 
                        __init_single_page(page, pfn, zid, nid);
-                       __free_pages_boot_core(page, pfn, 0);
-                       nr_pages++;
+                       if (!free_base_page) {
+                               free_base_page = page;
+                               free_base_pfn = pfn;
+                               nr_to_free = 0;
+                       }
+                       nr_to_free++;
+
+                       /* Where possible, batch up pages for a single free */
+                       continue;
+free_range:
+                       /* Free the current block of pages to allocator */
+                       nr_pages += nr_to_free;
+                       deferred_free_range(free_base_page, free_base_pfn,
+                                                               nr_to_free);
+                       free_base_page = NULL;
+                       free_base_pfn = nr_to_free = 0;
                }
+
                first_init_pfn = max(end_pfn, first_init_pfn);
        }
 
        /* Sanity check that the next zone really is unpopulated */
        WARN_ON(++zid < MAX_NR_ZONES && populated_zone(++zone));
 
-       pr_info("kswapd %d initialised %lu pages in %ums\n", nid, nr_pages,
+       pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
                                        jiffies_to_msecs(jiffies - start));
+       up_read(&pgdat_init_rwsem);
+       return 0;
+}
+
+void __init page_alloc_init_late(void)
+{
+       int nid;
+
+       for_each_node_state(nid, N_MEMORY) {
+               down_read(&pgdat_init_rwsem);
+               kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);
+       }
+
+       /* Block until all are initialised */
+       down_write(&pgdat_init_rwsem);
+       up_write(&pgdat_init_rwsem);
 }
 #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
 
@@ -1900,6 +1948,7 @@ void free_hot_cold_page_list(struct list_head *list, bool cold)
 void split_page(struct page *page, unsigned int order)
 {
        int i;
+       gfp_t gfp_mask;
 
        VM_BUG_ON_PAGE(PageCompound(page), page);
        VM_BUG_ON_PAGE(!page_count(page), page);
@@ -1913,10 +1962,11 @@ void split_page(struct page *page, unsigned int order)
                split_page(virt_to_page(page[0].shadow), order);
 #endif
 
-       set_page_owner(page, 0, 0);
+       gfp_mask = get_page_owner_gfp(page);
+       set_page_owner(page, 0, gfp_mask);
        for (i = 1; i < (1 << order); i++) {
                set_page_refcounted(page + i);
-               set_page_owner(page + i, 0, 0);
+               set_page_owner(page + i, 0, gfp_mask);
        }
 }
 EXPORT_SYMBOL_GPL(split_page);
@@ -1946,6 +1996,8 @@ int __isolate_free_page(struct page *page, unsigned int order)
        zone->free_area[order].nr_free--;
        rmv_page_order(page);
 
+       set_page_owner(page, order, __GFP_MOVABLE);
+
        /* Set the pageblock if the isolated page is at least a pageblock */
        if (order >= pageblock_order - 1) {
                struct page *endpage = page + (1 << order) - 1;
@@ -1957,7 +2009,7 @@ int __isolate_free_page(struct page *page, unsigned int order)
                }
        }
 
-       set_page_owner(page, order, 0);
+
        return 1UL << order;
 }
 
@@ -4550,7 +4602,29 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
                                                &nr_initialised))
                                break;
                }
-               __init_single_pfn(pfn, zone, nid);
+
+               /*
+                * Mark the block movable so that blocks are reserved for
+                * movable at startup. This will force kernel allocations
+                * to reserve their blocks rather than leaking throughout
+                * the address space during boot when many long-lived
+                * kernel allocations are made. Later some blocks near
+                * the start are marked MIGRATE_RESERVE by
+                * setup_zone_migrate_reserve()
+                *
+                * bitmap is created for zone's valid pfn range. but memmap
+                * can be created for invalid pages (for alignment)
+                * check here not to call set_pageblock_migratetype() against
+                * pfn out of zone.
+                */
+               if (!(pfn & (pageblock_nr_pages - 1))) {
+                       struct page *page = pfn_to_page(pfn);
+
+                       __init_single_page(page, pfn, zone, nid);
+                       set_pageblock_migratetype(page, MIGRATE_MOVABLE);
+               } else {
+                       __init_single_pfn(pfn, zone, nid);
+               }
        }
 }