]> Git Repo - linux.git/blobdiff - mm/sparse.c
memblock: stop using implicit alignment to SMP_CACHE_BYTES
[linux.git] / mm / sparse.c
index f13f2723950ad4c06502c15df16cd8f7acb8e4c3..33307fc05c4d3372d5e4746116330532765e61d7 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/mmzone.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/compiler.h>
 #include <linux/highmem.h>
 #include <linux/export.h>
@@ -68,7 +68,8 @@ static noinline struct mem_section __ref *sparse_index_alloc(int nid)
        if (slab_is_available())
                section = kzalloc_node(array_size, GFP_KERNEL, nid);
        else
-               section = memblock_virt_alloc_node(array_size, nid);
+               section = memblock_alloc_node(array_size, SMP_CACHE_BYTES,
+                                             nid);
 
        return section;
 }
@@ -200,6 +201,11 @@ static inline int next_present_section_nr(int section_nr)
              (section_nr <= __highest_present_section_nr));    \
             section_nr = next_present_section_nr(section_nr))
 
+static inline unsigned long first_present_section_nr(void)
+{
+       return next_present_section_nr(-1);
+}
+
 /* Record a memory area against a node. */
 void __init memory_present(int nid, unsigned long start, unsigned long end)
 {
@@ -211,7 +217,7 @@ void __init memory_present(int nid, unsigned long start, unsigned long end)
 
                size = sizeof(struct mem_section*) * NR_SECTION_ROOTS;
                align = 1 << (INTERNODE_CACHE_SHIFT);
-               mem_section = memblock_virt_alloc(size, align);
+               mem_section = memblock_alloc(size, align);
        }
 #endif
 
@@ -257,19 +263,14 @@ struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pn
        return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum);
 }
 
-static int __meminit sparse_init_one_section(struct mem_section *ms,
+static void __meminit sparse_init_one_section(struct mem_section *ms,
                unsigned long pnum, struct page *mem_map,
                unsigned long *pageblock_bitmap)
 {
-       if (!present_section(ms))
-               return -EINVAL;
-
        ms->section_mem_map &= ~SECTION_MAP_MASK;
        ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum) |
                                                        SECTION_HAS_MEM_MAP;
        ms->pageblock_flags = pageblock_bitmap;
-
-       return 1;
 }
 
 unsigned long usemap_size(void)
@@ -306,7 +307,7 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
        limit = goal + (1UL << PA_SECTION_SHIFT);
        nid = early_pfn_to_nid(goal >> PAGE_SHIFT);
 again:
-       p = memblock_virt_alloc_try_nid_nopanic(size,
+       p = memblock_alloc_try_nid_nopanic(size,
                                                SMP_CACHE_BYTES, goal, limit,
                                                nid);
        if (!p && limit) {
@@ -362,7 +363,7 @@ static unsigned long * __init
 sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
                                         unsigned long size)
 {
-       return memblock_virt_alloc_node_nopanic(size, pgdat->node_id);
+       return memblock_alloc_node_nopanic(size, pgdat->node_id);
 }
 
 static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
@@ -370,160 +371,121 @@ static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
-static void __init sparse_early_usemaps_alloc_node(void *data,
-                                unsigned long pnum_begin,
-                                unsigned long pnum_end,
-                                unsigned long usemap_count, int nodeid)
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+static unsigned long __init section_map_size(void)
 {
-       void *usemap;
-       unsigned long pnum;
-       unsigned long **usemap_map = (unsigned long **)data;
-       int size = usemap_size();
-
-       usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid),
-                                                         size * usemap_count);
-       if (!usemap) {
-               pr_warn("%s: allocation failed\n", __func__);
-               return;
-       }
+       return ALIGN(sizeof(struct page) * PAGES_PER_SECTION, PMD_SIZE);
+}
 
-       for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
-               if (!present_section_nr(pnum))
-                       continue;
-               usemap_map[pnum] = usemap;
-               usemap += size;
-               check_usemap_section_nr(nodeid, usemap_map[pnum]);
-       }
+#else
+static unsigned long __init section_map_size(void)
+{
+       return PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION);
 }
 
-#ifndef CONFIG_SPARSEMEM_VMEMMAP
 struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid,
                struct vmem_altmap *altmap)
 {
-       struct page *map;
-       unsigned long size;
+       unsigned long size = section_map_size();
+       struct page *map = sparse_buffer_alloc(size);
+
+       if (map)
+               return map;
 
-       size = PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION);
-       map = memblock_virt_alloc_try_nid(size,
+       map = memblock_alloc_try_nid(size,
                                          PAGE_SIZE, __pa(MAX_DMA_ADDRESS),
-                                         BOOTMEM_ALLOC_ACCESSIBLE, nid);
+                                         MEMBLOCK_ALLOC_ACCESSIBLE, nid);
        return map;
 }
-void __init sparse_mem_maps_populate_node(struct page **map_map,
-                                         unsigned long pnum_begin,
-                                         unsigned long pnum_end,
-                                         unsigned long map_count, int nodeid)
-{
-       void *map;
-       unsigned long pnum;
-       unsigned long size = sizeof(struct page) * PAGES_PER_SECTION;
-
-       size = PAGE_ALIGN(size);
-       map = memblock_virt_alloc_try_nid_raw(size * map_count,
-                                             PAGE_SIZE, __pa(MAX_DMA_ADDRESS),
-                                             BOOTMEM_ALLOC_ACCESSIBLE, nodeid);
-       if (map) {
-               for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
-                       if (!present_section_nr(pnum))
-                               continue;
-                       map_map[pnum] = map;
-                       map += size;
-               }
-               return;
-       }
+#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
 
-       /* fallback */
-       for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
-               struct mem_section *ms;
+static void *sparsemap_buf __meminitdata;
+static void *sparsemap_buf_end __meminitdata;
 
-               if (!present_section_nr(pnum))
-                       continue;
-               map_map[pnum] = sparse_mem_map_populate(pnum, nodeid, NULL);
-               if (map_map[pnum])
-                       continue;
-               ms = __nr_to_section(pnum);
-               pr_err("%s: sparsemem memory map backing failed some memory will not be available\n",
-                      __func__);
-               ms->section_mem_map = 0;
-       }
+static void __init sparse_buffer_init(unsigned long size, int nid)
+{
+       WARN_ON(sparsemap_buf); /* forgot to call sparse_buffer_fini()? */
+       sparsemap_buf =
+               memblock_alloc_try_nid_raw(size, PAGE_SIZE,
+                                               __pa(MAX_DMA_ADDRESS),
+                                               MEMBLOCK_ALLOC_ACCESSIBLE, nid);
+       sparsemap_buf_end = sparsemap_buf + size;
 }
-#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
 
-#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
-static void __init sparse_early_mem_maps_alloc_node(void *data,
-                                unsigned long pnum_begin,
-                                unsigned long pnum_end,
-                                unsigned long map_count, int nodeid)
+static void __init sparse_buffer_fini(void)
 {
-       struct page **map_map = (struct page **)data;
-       sparse_mem_maps_populate_node(map_map, pnum_begin, pnum_end,
-                                        map_count, nodeid);
+       unsigned long size = sparsemap_buf_end - sparsemap_buf;
+
+       if (sparsemap_buf && size > 0)
+               memblock_free_early(__pa(sparsemap_buf), size);
+       sparsemap_buf = NULL;
 }
-#else
-static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
-{
-       struct page *map;
-       struct mem_section *ms = __nr_to_section(pnum);
-       int nid = sparse_early_nid(ms);
 
-       map = sparse_mem_map_populate(pnum, nid, NULL);
-       if (map)
-               return map;
+void * __meminit sparse_buffer_alloc(unsigned long size)
+{
+       void *ptr = NULL;
 
-       pr_err("%s: sparsemem memory map backing failed some memory will not be available\n",
-              __func__);
-       ms->section_mem_map = 0;
-       return NULL;
+       if (sparsemap_buf) {
+               ptr = PTR_ALIGN(sparsemap_buf, size);
+               if (ptr + size > sparsemap_buf_end)
+                       ptr = NULL;
+               else
+                       sparsemap_buf = ptr + size;
+       }
+       return ptr;
 }
-#endif
 
 void __weak __meminit vmemmap_populate_print_last(void)
 {
 }
 
-/**
- *  alloc_usemap_and_memmap - memory alloction for pageblock flags and vmemmap
- *  @map: usemap_map for pageblock flags or mmap_map for vmemmap
+/*
+ * Initialize sparse on a specific node. The node spans [pnum_begin, pnum_end)
+ * And number of present sections in this node is map_count.
  */
-static void __init alloc_usemap_and_memmap(void (*alloc_func)
-                                       (void *, unsigned long, unsigned long,
-                                       unsigned long, int), void *data)
+static void __init sparse_init_nid(int nid, unsigned long pnum_begin,
+                                  unsigned long pnum_end,
+                                  unsigned long map_count)
 {
-       unsigned long pnum;
-       unsigned long map_count;
-       int nodeid_begin = 0;
-       unsigned long pnum_begin = 0;
-
-       for_each_present_section_nr(0, pnum) {
-               struct mem_section *ms;
+       unsigned long pnum, usemap_longs, *usemap;
+       struct page *map;
 
-               ms = __nr_to_section(pnum);
-               nodeid_begin = sparse_early_nid(ms);
-               pnum_begin = pnum;
-               break;
+       usemap_longs = BITS_TO_LONGS(SECTION_BLOCKFLAGS_BITS);
+       usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nid),
+                                                         usemap_size() *
+                                                         map_count);
+       if (!usemap) {
+               pr_err("%s: node[%d] usemap allocation failed", __func__, nid);
+               goto failed;
        }
-       map_count = 1;
-       for_each_present_section_nr(pnum_begin + 1, pnum) {
+       sparse_buffer_init(map_count * section_map_size(), nid);
+       for_each_present_section_nr(pnum_begin, pnum) {
+               if (pnum >= pnum_end)
+                       break;
+
+               map = sparse_mem_map_populate(pnum, nid, NULL);
+               if (!map) {
+                       pr_err("%s: node[%d] memory map backing failed. Some memory will not be available.",
+                              __func__, nid);
+                       pnum_begin = pnum;
+                       goto failed;
+               }
+               check_usemap_section_nr(nid, usemap);
+               sparse_init_one_section(__nr_to_section(pnum), pnum, map, usemap);
+               usemap += usemap_longs;
+       }
+       sparse_buffer_fini();
+       return;
+failed:
+       /* We failed to allocate, mark all the following pnums as not present */
+       for_each_present_section_nr(pnum_begin, pnum) {
                struct mem_section *ms;
-               int nodeid;
 
+               if (pnum >= pnum_end)
+                       break;
                ms = __nr_to_section(pnum);
-               nodeid = sparse_early_nid(ms);
-               if (nodeid == nodeid_begin) {
-                       map_count++;
-                       continue;
-               }
-               /* ok, we need to take cake of from pnum_begin to pnum - 1*/
-               alloc_func(data, pnum_begin, pnum,
-                                               map_count, nodeid_begin);
-               /* new start, update count etc*/
-               nodeid_begin = nodeid;
-               pnum_begin = pnum;
-               map_count = 1;
+               ms->section_mem_map = 0;
        }
-       /* ok, last chunk */
-       alloc_func(data, pnum_begin, __highest_present_section_nr+1,
-                                               map_count, nodeid_begin);
 }
 
 /*
@@ -532,72 +494,29 @@ static void __init alloc_usemap_and_memmap(void (*alloc_func)
  */
 void __init sparse_init(void)
 {
-       unsigned long pnum;
-       struct page *map;
-       unsigned long *usemap;
-       unsigned long **usemap_map;
-       int size;
-#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
-       int size2;
-       struct page **map_map;
-#endif
-
-       /* see include/linux/mmzone.h 'struct mem_section' definition */
-       BUILD_BUG_ON(!is_power_of_2(sizeof(struct mem_section)));
+       unsigned long pnum_begin = first_present_section_nr();
+       int nid_begin = sparse_early_nid(__nr_to_section(pnum_begin));
+       unsigned long pnum_end, map_count = 1;
 
        /* Setup pageblock_order for HUGETLB_PAGE_SIZE_VARIABLE */
        set_pageblock_order();
 
-       /*
-        * map is using big page (aka 2M in x86 64 bit)
-        * usemap is less one page (aka 24 bytes)
-        * so alloc 2M (with 2M align) and 24 bytes in turn will
-        * make next 2M slip to one more 2M later.
-        * then in big system, the memory will have a lot of holes...
-        * here try to allocate 2M pages continuously.
-        *
-        * powerpc need to call sparse_init_one_section right after each
-        * sparse_early_mem_map_alloc, so allocate usemap_map at first.
-        */
-       size = sizeof(unsigned long *) * NR_MEM_SECTIONS;
-       usemap_map = memblock_virt_alloc(size, 0);
-       if (!usemap_map)
-               panic("can not allocate usemap_map\n");
-       alloc_usemap_and_memmap(sparse_early_usemaps_alloc_node,
-                                                       (void *)usemap_map);
-
-#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
-       size2 = sizeof(struct page *) * NR_MEM_SECTIONS;
-       map_map = memblock_virt_alloc(size2, 0);
-       if (!map_map)
-               panic("can not allocate map_map\n");
-       alloc_usemap_and_memmap(sparse_early_mem_maps_alloc_node,
-                                                       (void *)map_map);
-#endif
+       for_each_present_section_nr(pnum_begin + 1, pnum_end) {
+               int nid = sparse_early_nid(__nr_to_section(pnum_end));
 
-       for_each_present_section_nr(0, pnum) {
-               usemap = usemap_map[pnum];
-               if (!usemap)
-                       continue;
-
-#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
-               map = map_map[pnum];
-#else
-               map = sparse_early_mem_map_alloc(pnum);
-#endif
-               if (!map)
+               if (nid == nid_begin) {
+                       map_count++;
                        continue;
-
-               sparse_init_one_section(__nr_to_section(pnum), pnum, map,
-                                                               usemap);
+               }
+               /* Init node with sections in range [pnum_begin, pnum_end) */
+               sparse_init_nid(nid_begin, pnum_begin, pnum_end, map_count);
+               nid_begin = nid;
+               pnum_begin = pnum_end;
+               map_count = 1;
        }
-
+       /* cover the last node */
+       sparse_init_nid(nid_begin, pnum_begin, pnum_end, map_count);
        vmemmap_populate_print_last();
-
-#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
-       memblock_free_early(__pa(map_map), size2);
-#endif
-       memblock_free_early(__pa(usemap_map), size);
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
@@ -760,6 +679,7 @@ int __meminit sparse_add_one_section(struct pglist_data *pgdat,
        ret = sparse_index_init(section_nr, pgdat->node_id);
        if (ret < 0 && ret != -EEXIST)
                return ret;
+       ret = 0;
        memmap = kmalloc_section_memmap(section_nr, pgdat->node_id, altmap);
        if (!memmap)
                return -ENOMEM;
@@ -777,21 +697,18 @@ int __meminit sparse_add_one_section(struct pglist_data *pgdat,
                goto out;
        }
 
-#ifdef CONFIG_DEBUG_VM
        /*
         * Poison uninitialized struct pages in order to catch invalid flags
         * combinations.
         */
-       memset(memmap, PAGE_POISON_PATTERN, sizeof(struct page) * PAGES_PER_SECTION);
-#endif
+       page_init_poison(memmap, sizeof(struct page) * PAGES_PER_SECTION);
 
        section_mark_present(ms);
-
-       ret = sparse_init_one_section(ms, section_nr, memmap, usemap);
+       sparse_init_one_section(ms, section_nr, memmap, usemap);
 
 out:
        pgdat_resize_unlock(pgdat, &flags);
-       if (ret <= 0) {
+       if (ret < 0) {
                kfree(usemap);
                __kfree_section_memmap(memmap, altmap);
        }
This page took 0.050834 seconds and 4 git commands to generate.