[PATCH] x86_64: Try to allocate node memmap near the end of node
Andi Kleen [Sat, 25 Mar 2006 15:31:10 +0000 (16:31 +0100)]
This fixes problems with very large nodes (over 128GB) filling up all of
the first 4GB with their mem_map and not leaving enough space for the
swiotlb.

Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

arch/x86_64/mm/numa.c
include/linux/bootmem.h
mm/bootmem.c

index e4b6275..07471a3 100644 (file)
@@ -149,7 +149,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
 /* Initialize final allocator for a zone */
 void __init setup_node_zones(int nodeid)
 { 
-       unsigned long start_pfn, end_pfn; 
+       unsigned long start_pfn, end_pfn, memmapsize, limit;
        unsigned long zones[MAX_NR_ZONES];
        unsigned long holes[MAX_NR_ZONES];
 
@@ -159,6 +159,16 @@ void __init setup_node_zones(int nodeid)
        Dprintk(KERN_INFO "Setting up node %d %lx-%lx\n",
                nodeid, start_pfn, end_pfn);
 
+       /* Try to allocate mem_map at end to not fill up precious <4GB
+          memory. */
+       memmapsize = sizeof(struct page) * (end_pfn-start_pfn);
+       limit = end_pfn << PAGE_SHIFT;
+       NODE_DATA(nodeid)->node_mem_map = 
+               __alloc_bootmem_core(NODE_DATA(nodeid)->bdata, 
+                               memmapsize, SMP_CACHE_BYTES, 
+                               round_down(limit - memmapsize, PAGE_SIZE), 
+                               limit);
+
        size_zones(zones, holes, start_pfn, end_pfn);
        free_area_init_node(nodeid, NODE_DATA(nodeid), zones,
                            start_pfn, holes);
index 993da8c..7155452 100644 (file)
@@ -51,6 +51,9 @@ extern void * __init __alloc_bootmem_low_node(pg_data_t *pgdat,
                                              unsigned long size,
                                              unsigned long align,
                                              unsigned long goal);
+extern void * __init __alloc_bootmem_core(struct bootmem_data *bdata,
+               unsigned long size, unsigned long align, unsigned long goal,
+               unsigned long limit);
 #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE
 extern void __init reserve_bootmem (unsigned long addr, unsigned long size);
 #define alloc_bootmem(x) \
index 35c3229..b55bd39 100644 (file)
@@ -152,7 +152,7 @@ static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
  *
  * NOTE:  This function is _not_ reentrant.
  */
-static void * __init
+void * __init
 __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
              unsigned long align, unsigned long goal, unsigned long limit)
 {