[PATCH] powerpc: Fix sparsemem with memory holes [was Re: ppc64 oops..]
authorPaul Mackerras <paulus@samba.org>
Wed, 16 Nov 2005 00:43:26 +0000 (11:43 +1100)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 16 Nov 2005 00:57:12 +0000 (16:57 -0800)
This patch should fix the crashes we have been seeing on 64-bit
powerpc systems with a memory hole when sparsemem is enabled.
I'd appreciate it if people who know more about NUMA and sparsemem
than me could look over it.

There were two bugs.  The first was that if NUMA was enabled but there
was no NUMA information for the machine, the setup_nonnuma() function
was adding a single region, assuming memory was contiguous.  The
second was that the loops in mem_init() and show_mem() assumed that
all pages within the span of a pgdat were valid (had a valid struct
page).

I also fixed the incorrect setting of num_physpages that Mike Kravetz
pointed out.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c

index e2c95fcb8055186cf2e4d452d0d125c86e024820..4bd7b0a70996a6e569790ef8652241d61edb37ba 100644 (file)
@@ -200,6 +200,8 @@ void show_mem(void)
                unsigned long flags;
                pgdat_resize_lock(pgdat, &flags);
                for (i = 0; i < pgdat->node_spanned_pages; i++) {
+                       if (!pfn_valid(pgdat->node_start_pfn + i))
+                               continue;
                        page = pgdat_page_nr(pgdat, i);
                        total++;
                        if (PageHighMem(page))
@@ -336,7 +338,7 @@ void __init mem_init(void)
        struct page *page;
        unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
 
-       num_physpages = max_pfn;        /* RAM is assumed contiguous */
+       num_physpages = lmb.memory.size >> PAGE_SHIFT;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
 #ifdef CONFIG_NEED_MULTIPLE_NODES
@@ -348,11 +350,13 @@ void __init mem_init(void)
                }
        }
 #else
-       max_mapnr = num_physpages;
+       max_mapnr = max_pfn;
        totalram_pages += free_all_bootmem();
 #endif
        for_each_pgdat(pgdat) {
                for (i = 0; i < pgdat->node_spanned_pages; i++) {
+                       if (!pfn_valid(pgdat->node_start_pfn + i))
+                               continue;
                        page = pgdat_page_nr(pgdat, i);
                        if (PageReserved(page))
                                reservedpages++;
index bd2cf13368853f0518fbf5e018f8b2069b6998d8..f72cf87364cb29d9953131fc1f0ef46d5a407087 100644 (file)
@@ -483,6 +483,7 @@ static void __init setup_nonnuma(void)
 {
        unsigned long top_of_ram = lmb_end_of_DRAM();
        unsigned long total_ram = lmb_phys_mem_size();
+       unsigned int i;
 
        printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
               top_of_ram, total_ram);
@@ -490,7 +491,9 @@ static void __init setup_nonnuma(void)
               (top_of_ram - total_ram) >> 20);
 
        map_cpu_to_node(boot_cpuid, 0);
-       add_region(0, 0, lmb_end_of_DRAM() >> PAGE_SHIFT);
+       for (i = 0; i < lmb.memory.cnt; ++i)
+               add_region(0, lmb.memory.region[i].base >> PAGE_SHIFT,
+                          lmb_size_pages(&lmb.memory, i));
        node_set_online(0);
 }