ARM: Fix sparsemem with SPARSEMEM_EXTREME enabled
authorRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 29 Oct 2009 17:06:17 +0000 (17:06 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 29 Oct 2009 17:06:17 +0000 (17:06 +0000)
When SPARSEMEM_EXTREME is enabled, memory_present() wants to use bootmem
to allocate data structures.  However, we call memory_present() after
declaring memory to bootmem, but before we've reserved areas.

This leads to sparsemem data structures being overwritten later in the
kernel's initialization (when slab initializes.)

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mm/init.c

index 40940d7ce4ffed4cf5be70f3c149013c9c3d5bbc..52c40d15567242177b40c5c60943cf63c18e3ee1 100644 (file)
@@ -273,7 +273,6 @@ static void __init bootmem_init_node(int node, struct meminfo *mi,
                struct membank *bank = &mi->bank[i];
                if (!bank->highmem)
                        free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank));
-               memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank));
        }
 
        /*
@@ -370,6 +369,19 @@ int pfn_valid(unsigned long pfn)
        return 0;
 }
 EXPORT_SYMBOL(pfn_valid);
+
+static void arm_memory_present(struct meminfo *mi, int node)
+{
+}
+#else
+static void arm_memory_present(struct meminfo *mi, int node)
+{
+       int i;
+       for_each_nodebank(i, mi, node) {
+               struct membank *bank = &mi->bank[i];
+               memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank));
+       }
+}
 #endif
 
 static int __init meminfo_cmp(const void *_a, const void *_b)
@@ -427,6 +439,12 @@ void __init bootmem_init(void)
                 */
                if (node == initrd_node)
                        bootmem_reserve_initrd(node);
+
+               /*
+                * Sparsemem tries to allocate bootmem in memory_present(),
+                * so must be done after the fixed reservations
+                */
+               arm_memory_present(mi, node);
        }
 
        /*