Memoryless nodes: introduce mask of nodes with memory
Christoph Lameter [Tue, 16 Oct 2007 08:25:29 +0000 (01:25 -0700)]
It is necessary to know if nodes have memory since we have recently begun to
add support for memoryless nodes.  For that purpose we introduce a two new
node states: N_HIGH_MEMORY and N_NORMAL_MEMORY.

A node has its bit in N_HIGH_MEMORY set if it has any memory regardless of the
type of mmemory.  If a node has memory then it has at least one zone defined
in its pgdat structure that is located in the pgdat itself.

A node has its bit in N_NORMAL_MEMORY set if it has a lower zone than
ZONE_HIGHMEM.  This means it is possible to allocate memory that is not
subject to kmap.

N_HIGH_MEMORY and N_NORMAL_MEMORY can then be used in various places to insure
that we do the right thing when we encounter a memoryless node.

[akpm@linux-foundation.org: build fix]
[Lee.Schermerhorn@hp.com: update N_HIGH_MEMORY node state for memory hotadd]
[y-goto@jp.fujitsu.com: Fix memory hotplug + sparsemem build]
Signed-off-by: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Acked-by: Bob Picco <bob.picco@hp.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Mel Gorman <mel@skynet.ie>
Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

include/linux/nodemask.h
mm/memory_hotplug.c
mm/page_alloc.c

index 583e6b8..ccee962 100644 (file)
@@ -341,8 +341,14 @@ static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,
  * Bitmasks that are kept for all the nodes.
  */
 enum node_states {
-       N_POSSIBLE,     /* The node could become online at some point */
-       N_ONLINE,       /* The node is online */
+       N_POSSIBLE,             /* The node could become online at some point */
+       N_ONLINE,               /* The node is online */
+       N_NORMAL_MEMORY,        /* The node has regular memory */
+#ifdef CONFIG_HIGHMEM
+       N_HIGH_MEMORY,          /* The node has regular or high memory */
+#else
+       N_HIGH_MEMORY = N_NORMAL_MEMORY,
+#endif
        NR_NODE_STATES
 };
 
index df9d554..9c12ae5 100644 (file)
@@ -217,6 +217,10 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        zone->zone_pgdat->node_present_pages += onlined_pages;
 
        setup_per_zone_pages_min();
+       if (onlined_pages) {
+               kswapd_run(zone_to_nid(zone));
+               node_set_state(zone_to_nid(zone), N_HIGH_MEMORY);
+       }
 
        if (need_zonelists_rebuild)
                build_all_zonelists();
@@ -271,9 +275,6 @@ int add_memory(int nid, u64 start, u64 size)
                if (!pgdat)
                        return -ENOMEM;
                new_pgdat = 1;
-               ret = kswapd_run(nid);
-               if (ret)
-                       goto error;
        }
 
        /* call arch's memory hotadd */
index 0cc5b3e..07dfd89 100644 (file)
@@ -2080,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;
 }