]> err.no Git - linux-2.6/blobdiff - mm/page_alloc.c
Memoryless nodes: introduce mask of nodes with memory
[linux-2.6] / mm / page_alloc.c
index 3da85b81dabb32608fa065f8086de64f725f5af8..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;
@@ -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;
@@ -2059,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;
 }
@@ -2332,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));
@@ -2429,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;