]> err.no Git - linux-2.6/blobdiff - mm/sparse.c
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / mm / sparse.c
index a2183cb5d5242a0f05695f00b65d5f0f6d25715e..7e9191381f86d0635e9ec68cda34cff6313ea859 100644 (file)
@@ -149,8 +149,18 @@ static inline int sparse_early_nid(struct mem_section *section)
 /* Record a memory area against a node. */
 void __init memory_present(int nid, unsigned long start, unsigned long end)
 {
+       unsigned long max_arch_pfn = 1UL << (MAX_PHYSMEM_BITS-PAGE_SHIFT);
        unsigned long pfn;
 
+       /*
+        * Sanity checks - do not allow an architecture to pass
+        * in larger pfns than the maximum scope of sparsemem:
+        */
+       if (start >= max_arch_pfn)
+               return;
+       if (end >= max_arch_pfn)
+               end = max_arch_pfn;
+
        start &= PAGE_SECTION_MASK;
        for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {
                unsigned long section = pfn_to_section_nr(pfn);
@@ -237,7 +247,7 @@ static unsigned long *__kmalloc_section_usemap(void)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
-static unsigned long *sparse_early_usemap_alloc(unsigned long pnum)
+static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum)
 {
        unsigned long *usemap;
        struct mem_section *ms = __nr_to_section(pnum);
@@ -285,6 +295,9 @@ struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
        return NULL;
 }
 
+void __attribute__((weak)) __meminit vmemmap_populate_print_last(void)
+{
+}
 /*
  * Allocate the accumulated non-linear sections, allocate a mem_map
  * for each and record the physical to section mapping.
@@ -294,22 +307,50 @@ void __init sparse_init(void)
        unsigned long pnum;
        struct page *map;
        unsigned long *usemap;
+       unsigned long **usemap_map;
+       int size;
+
+       /*
+        * 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 continously.
+        *
+        * 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 = alloc_bootmem(size);
+       if (!usemap_map)
+               panic("can not allocate usemap_map\n");
 
        for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
                if (!present_section_nr(pnum))
                        continue;
+               usemap_map[pnum] = sparse_early_usemap_alloc(pnum);
+       }
 
-               map = sparse_early_mem_map_alloc(pnum);
-               if (!map)
+       for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
+               if (!present_section_nr(pnum))
                        continue;
 
-               usemap = sparse_early_usemap_alloc(pnum);
+               usemap = usemap_map[pnum];
                if (!usemap)
                        continue;
 
+               map = sparse_early_mem_map_alloc(pnum);
+               if (!map)
+                       continue;
+
                sparse_init_one_section(__nr_to_section(pnum), pnum, map,
                                                                usemap);
        }
+
+       vmemmap_populate_print_last();
+
+       free_bootmem(__pa(usemap_map), size);
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
@@ -353,17 +394,9 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
        return __kmalloc_section_memmap(nr_pages);
 }
 
-static int vaddr_in_vmalloc_area(void *addr)
-{
-       if (addr >= (void *)VMALLOC_START &&
-           addr < (void *)VMALLOC_END)
-               return 1;
-       return 0;
-}
-
 static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
 {
-       if (vaddr_in_vmalloc_area(memmap))
+       if (is_vmalloc_addr(memmap))
                vfree(memmap);
        else
                free_pages((unsigned long)memmap,