]> err.no Git - linux-2.6/blobdiff - mm/page_alloc.c
Memoryless nodes: SLUB support
[linux-2.6] / mm / page_alloc.c
index 43cb3b3e1679ca4d9574f4a9d333f92b913bfb63..07dfd89992fa6d0ee90cf0ca6646a43d7dd926e2 100644 (file)
 #include "internal.h"
 
 /*
- * MCD - HACK: Find somewhere to initialize this EARLY, or make this
- * initializer cleaner
+ * Array of node states.
  */
-nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };
-EXPORT_SYMBOL(node_online_map);
-nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL;
-EXPORT_SYMBOL(node_possible_map);
+nodemask_t node_states[NR_NODE_STATES] __read_mostly = {
+       [N_POSSIBLE] = NODE_MASK_ALL,
+       [N_ONLINE] = { { [0] = 1UL } },
+#ifndef CONFIG_NUMA
+       [N_NORMAL_MEMORY] = { { [0] = 1UL } },
+#ifdef CONFIG_HIGHMEM
+       [N_HIGH_MEMORY] = { { [0] = 1UL } },
+#endif
+       [N_CPU] = { { [0] = 1UL } },
+#endif /* NUMA */
+};
+EXPORT_SYMBOL(node_states);
+
 unsigned long totalram_pages __read_mostly;
 unsigned long totalreserve_pages __read_mostly;
 long nr_swap_pages;
@@ -138,7 +146,7 @@ static unsigned long __meminitdata dma_reserve;
 #endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
   unsigned long __initdata required_kernelcore;
   unsigned long __initdata required_movablecore;
-  unsigned long __initdata zone_movable_pfn[MAX_NUMNODES];
+  unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
 
   /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
   int movable_zone;
@@ -726,7 +734,7 @@ static void __drain_pages(unsigned int cpu)
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_HIBERNATION
 
 void mark_free_pages(struct zone *zone)
 {
@@ -772,7 +780,7 @@ void drain_local_pages(void)
        __drain_pages(smp_processor_id());
        local_irq_restore(flags);       
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_HIBERNATION */
 
 /*
  * Free a 0-order page
@@ -1157,6 +1165,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
        nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */
        int zlc_active = 0;             /* set if using zonelist_cache */
        int did_zlc_setup = 0;          /* just call zlc_setup() one time */
+       enum zone_type highest_zoneidx = -1; /* Gets set for policy zonelists */
 
 zonelist_scan:
        /*
@@ -1166,6 +1175,18 @@ zonelist_scan:
        z = zonelist->zones;
 
        do {
+               /*
+                * In NUMA, this could be a policy zonelist which contains
+                * zones that may not be allowed by the current gfp_mask.
+                * Check the zone is allowed by the current flags
+                */
+               if (unlikely(alloc_should_filter_zonelist(zonelist))) {
+                       if (highest_zoneidx == -1)
+                               highest_zoneidx = gfp_zone(gfp_mask);
+                       if (zone_idx(*z) > highest_zoneidx)
+                               continue;
+               }
+
                if (NUMA_BUILD && zlc_active &&
                        !zlc_zone_worth_trying(zonelist, z, allowednodes))
                                continue;
@@ -1350,6 +1371,10 @@ nofail_alloc:
                if (page)
                        goto got_pg;
 
+               /* The OOM killer will not help higher order allocs so fail */
+               if (order > PAGE_ALLOC_COSTLY_ORDER)
+                       goto nopage;
+
                out_of_memory(zonelist, gfp_mask, order);
                goto restart;
        }
@@ -2055,14 +2080,35 @@ static void build_zonelist_cache(pg_data_t *pgdat)
 
 #endif /* CONFIG_NUMA */
 
+/* Any regular memory on that node ? */
+static void check_for_regular_memory(pg_data_t *pgdat)
+{
+#ifdef CONFIG_HIGHMEM
+       enum zone_type zone_type;
+
+       for (zone_type = 0; zone_type <= ZONE_NORMAL; zone_type++) {
+               struct zone *zone = &pgdat->node_zones[zone_type];
+               if (zone->present_pages)
+                       node_set_state(zone_to_nid(zone), N_NORMAL_MEMORY);
+       }
+#endif
+}
+
 /* return values int ....just for stop_machine_run() */
 static int __build_all_zonelists(void *dummy)
 {
        int nid;
 
        for_each_online_node(nid) {
-               build_zonelists(NODE_DATA(nid));
-               build_zonelist_cache(NODE_DATA(nid));
+               pg_data_t *pgdat = NODE_DATA(nid);
+
+               build_zonelists(pgdat);
+               build_zonelist_cache(pgdat);
+
+               /* Any memory on that node */
+               if (pgdat->node_present_pages)
+                       node_set_state(nid, N_HIGH_MEMORY);
+               check_for_regular_memory(pgdat);
        }
        return 0;
 }
@@ -2328,6 +2374,8 @@ static int __cpuinit process_zones(int cpu)
        return 0;
 bad:
        for_each_zone(dzone) {
+               if (!populated_zone(dzone))
+                       continue;
                if (dzone == zone)
                        break;
                kfree(zone_pcp(dzone, cpu));
@@ -2425,7 +2473,7 @@ int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
                 * To use this new node's memory, further consideration will be
                 * necessary.
                 */
-               zone->wait_table = (wait_queue_head_t *)vmalloc(alloc_size);
+               zone->wait_table = vmalloc(alloc_size);
        }
        if (!zone->wait_table)
                return -ENOMEM;
@@ -2775,11 +2823,11 @@ unsigned long __meminit __absent_pages_in_range(int nid,
        if (i == -1)
                return 0;
 
+       prev_end_pfn = min(early_node_map[i].start_pfn, range_end_pfn);
+
        /* Account for ranges before physical memory on this node */
        if (early_node_map[i].start_pfn > range_start_pfn)
-               hole_pages = early_node_map[i].start_pfn - range_start_pfn;
-
-       prev_end_pfn = early_node_map[i].start_pfn;
+               hole_pages = prev_end_pfn - range_start_pfn;
 
        /* Find all holes for the zone within the node */
        for (; i != -1; i = next_active_region_index_in_nid(i, nid)) {