Merge tag 'tag-chrome-platform-for-v4.20' of git://git.kernel.org/pub/scm/linux/kerne...
[linux-2.6-block.git] / mm / page_alloc.c
index c26d3152f9ba9619ec2b3fc95d02a79698b498e5..a919ba5cb3c845e03e4a070eff354acf19ec7c4a 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/interrupt.h>
 #include <linux/pagemap.h>
 #include <linux/jiffies.h>
-#include <linux/bootmem.h>
 #include <linux/memblock.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
@@ -1339,7 +1338,7 @@ meminit_pfn_in_nid(unsigned long pfn, int node,
 #endif
 
 
-void __init __free_pages_bootmem(struct page *page, unsigned long pfn,
+void __init memblock_free_pages(struct page *page, unsigned long pfn,
                                                        unsigned int order)
 {
        if (early_page_uninitialised(pfn))
@@ -5476,7 +5475,7 @@ overlap_memmap_init(unsigned long zone, unsigned long *pfn)
 
 /*
  * Initially all pages are reserved - free ones are freed
- * up by free_all_bootmem() once the early boot process is
+ * up by memblock_free_all() once the early boot process is
  * done. Non-atomic initialization, single-pass.
  */
 void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
@@ -6209,7 +6208,7 @@ static void __ref setup_usemap(struct pglist_data *pgdat,
        zone->pageblock_flags = NULL;
        if (usemapsize)
                zone->pageblock_flags =
-                       memblock_virt_alloc_node_nopanic(usemapsize,
+                       memblock_alloc_node_nopanic(usemapsize,
                                                         pgdat->node_id);
 }
 #else
@@ -6439,7 +6438,7 @@ static void __ref alloc_node_mem_map(struct pglist_data *pgdat)
                end = pgdat_end_pfn(pgdat);
                end = ALIGN(end, MAX_ORDER_NR_PAGES);
                size =  (end - start) * sizeof(struct page);
-               map = memblock_virt_alloc_node_nopanic(size, pgdat->node_id);
+               map = memblock_alloc_node_nopanic(size, pgdat->node_id);
                pgdat->node_mem_map = map + offset;
        }
        pr_debug("%s: node %d, pgdat %08lx, node_mem_map %08lx\n",
@@ -6508,48 +6507,67 @@ void __init free_area_init_node(int nid, unsigned long *zones_size,
        free_area_init_core(pgdat);
 }
 
-#if defined(CONFIG_HAVE_MEMBLOCK) && !defined(CONFIG_FLAT_NODE_MEM_MAP)
+#if !defined(CONFIG_FLAT_NODE_MEM_MAP)
+/*
+ * Zero all valid struct pages in range [spfn, epfn), return number of struct
+ * pages zeroed
+ */
+static u64 zero_pfn_range(unsigned long spfn, unsigned long epfn)
+{
+       unsigned long pfn;
+       u64 pgcnt = 0;
+
+       for (pfn = spfn; pfn < epfn; pfn++) {
+               if (!pfn_valid(ALIGN_DOWN(pfn, pageblock_nr_pages))) {
+                       pfn = ALIGN_DOWN(pfn, pageblock_nr_pages)
+                               + pageblock_nr_pages - 1;
+                       continue;
+               }
+               mm_zero_struct_page(pfn_to_page(pfn));
+               pgcnt++;
+       }
+
+       return pgcnt;
+}
+
 /*
  * Only struct pages that are backed by physical memory are zeroed and
  * initialized by going through __init_single_page(). But, there are some
  * struct pages which are reserved in memblock allocator and their fields
  * may be accessed (for example page_to_pfn() on some configuration accesses
  * flags). We must explicitly zero those struct pages.
+ *
+ * This function also addresses a similar issue where struct pages are left
+ * uninitialized because the physical address range is not covered by
+ * memblock.memory or memblock.reserved. That could happen when memblock
+ * layout is manually configured via memmap=.
  */
 void __init zero_resv_unavail(void)
 {
        phys_addr_t start, end;
-       unsigned long pfn;
        u64 i, pgcnt;
+       phys_addr_t next = 0;
 
        /*
-        * Loop through ranges that are reserved, but do not have reported
-        * physical memory backing.
+        * Loop through unavailable ranges not covered by memblock.memory.
         */
        pgcnt = 0;
-       for_each_resv_unavail_range(i, &start, &end) {
-               for (pfn = PFN_DOWN(start); pfn < PFN_UP(end); pfn++) {
-                       if (!pfn_valid(ALIGN_DOWN(pfn, pageblock_nr_pages))) {
-                               pfn = ALIGN_DOWN(pfn, pageblock_nr_pages)
-                                       + pageblock_nr_pages - 1;
-                               continue;
-                       }
-                       mm_zero_struct_page(pfn_to_page(pfn));
-                       pgcnt++;
-               }
+       for_each_mem_range(i, &memblock.memory, NULL,
+                       NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, NULL) {
+               if (next < start)
+                       pgcnt += zero_pfn_range(PFN_DOWN(next), PFN_UP(start));
+               next = end;
        }
+       pgcnt += zero_pfn_range(PFN_DOWN(next), max_pfn);
 
        /*
         * Struct pages that do not have backing memory. This could be because
         * firmware is using some of this memory, or for some other reasons.
-        * Once memblock is changed so such behaviour is not allowed: i.e.
-        * list of "reserved" memory must be a subset of list of "memory", then
-        * this code can be removed.
         */
        if (pgcnt)
-               pr_info("Reserved but unavailable: %lld pages", pgcnt);
+               pr_info("Zeroed struct page in unavailable ranges: %lld pages", pgcnt);
 }
-#endif /* CONFIG_HAVE_MEMBLOCK && !CONFIG_FLAT_NODE_MEM_MAP */
+#endif /* !CONFIG_FLAT_NODE_MEM_MAP */
 
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 
@@ -7692,9 +7710,11 @@ void *__init alloc_large_system_hash(const char *tablename,
                size = bucketsize << log2qty;
                if (flags & HASH_EARLY) {
                        if (flags & HASH_ZERO)
-                               table = memblock_virt_alloc_nopanic(size, 0);
+                               table = memblock_alloc_nopanic(size,
+                                                              SMP_CACHE_BYTES);
                        else
-                               table = memblock_virt_alloc_raw(size, 0);
+                               table = memblock_alloc_raw(size,
+                                                          SMP_CACHE_BYTES);
                } else if (hashdist) {
                        table = __vmalloc(size, gfp_flags, PAGE_KERNEL);
                } else {