

---

 memhotplug-dave/include/linux/memory.h |    1 
 memhotplug-dave/mm/memory_hotplug.c    |   11 ++++++
 memhotplug-dave/mm/page_alloc.c        |   55 +++++++++++++++++++++++++--------
 3 files changed, 55 insertions(+), 12 deletions(-)

diff -puN include/linux/memory.h~Y0-empty-zone include/linux/memory.h
--- memhotplug/include/linux/memory.h~Y0-empty-zone	2005-01-04 13:50:00.000000000 -0800
+++ memhotplug-dave/include/linux/memory.h	2005-01-04 13:50:00.000000000 -0800
@@ -58,6 +58,7 @@ extern int register_memory(struct memory
 extern int register_new_memory(unsigned int section);
 extern int unregister_memory_section(unsigned int phys_section_nr);
 extern int invalidate_phys_mapping(unsigned long pfn, unsigned long nr_pages);
+extern int hot_add_zone_init(struct zone *zone, unsigned long phys_start_pfn, unsigned long size_pages);
 struct notifier_block;
 
 extern int register_memory_notifier(struct notifier_block *nb);
diff -puN mm/memory_hotplug.c~Y0-empty-zone mm/memory_hotplug.c
--- memhotplug/mm/memory_hotplug.c~Y0-empty-zone	2005-01-04 13:50:00.000000000 -0800
+++ memhotplug-dave/mm/memory_hotplug.c	2005-01-04 13:50:00.000000000 -0800
@@ -68,6 +68,17 @@ int __add_section(struct zone *zone, uns
 	}
 	alloc_memsections(phys_start_pfn, phys_start_pfn, nr_pages);
 
+	if (zone->zone_start_pfn > phys_start_pfn) {
+		zone->spanned_pages += zone->zone_start_pfn - phys_start_pfn;
+		zone->zone_start_pfn = phys_start_pfn;
+	}
+	if (phys_start_pfn + nr_pages > zone->zone_start_pfn + zone->spanned_pages) {
+		zone->spanned_pages = (phys_start_pfn + nr_pages) -
+					zone->zone_start_pfn;
+	}
+
+	hot_add_zone_init(zone, phys_start_pfn, PAGES_PER_SECTION);
+
 	up(&zone->resize_sem);
 
 	memmap = __kmalloc_section_memmap(nr_pages);
diff -puN mm/page_alloc.c~Y0-empty-zone mm/page_alloc.c
--- memhotplug/mm/page_alloc.c~Y0-empty-zone	2005-01-04 13:50:00.000000000 -0800
+++ memhotplug-dave/mm/page_alloc.c	2005-01-04 13:50:00.000000000 -0800
@@ -1609,7 +1609,7 @@ void show_free_areas(void)
 /*
  * Builds allocation fallback zone lists.
  */
-static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist, int j, int k)
+int __devinit build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist, int j, int k)
 {
 	switch (k) {
 		struct zone *zone;
@@ -1617,7 +1617,12 @@ static int __init build_zonelists_node(p
 		BUG();
 	case ZONE_HIGHMEM:
 		zone = pgdat->node_zones + ZONE_HIGHMEM;
-		if (zone->present_pages) {
+		/*
+		 * with mem hotplug we don't increment present_pages
+		 * until the pages are actually freed into the zone,
+		 * but we increment spanned pages much earlier
+		 */
+		if (zone->spanned_pages) {
 #ifndef CONFIG_HIGHMEM
 			BUG();
 #endif
@@ -1625,11 +1630,11 @@ static int __init build_zonelists_node(p
 		}
 	case ZONE_NORMAL:
 		zone = pgdat->node_zones + ZONE_NORMAL;
-		if (zone->present_pages)
+		if (zone->spanned_pages)
 			zonelist->zones[j++] = zone;
 	case ZONE_DMA:
 		zone = pgdat->node_zones + ZONE_DMA;
-		if (zone->present_pages)
+		if (zone->spanned_pages)
 			zonelist->zones[j++] = zone;
 	}
 
@@ -1700,7 +1705,7 @@ static int __init find_next_best_node(in
 	return best_node;
 }
 
-static void __init build_zonelists(pg_data_t *pgdat)
+void __devinit build_zonelists(pg_data_t *pgdat)
 {
 	int i, j, k, node, local_node;
 	int prev_node, load;
@@ -1747,7 +1752,7 @@ static void __init build_zonelists(pg_da
 
 #else	/* CONFIG_NUMA */
 
-static void __init build_zonelists(pg_data_t *pgdat)
+void __devinit build_zonelists(pg_data_t *pgdat)
 {
 	int i, j, k, node, local_node;
 
@@ -1904,7 +1909,7 @@ void zone_init_free_lists(struct pglist_
 	memmap_init_zone((size), (nid), (zone), (start_pfn))
 #endif
 
-static __devinit void zone_pcp_init(struct zone *zone)
+void zone_pcp_init(struct zone *zone)
 {
 	unsigned long batch;
 	int cpu;
@@ -1942,7 +1947,7 @@ static __devinit void zone_pcp_init(stru
 	}
 }
 
-static __devinit void zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
+void zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
 {
 	int table_size_bytes;
 	int i;
@@ -1969,7 +1974,6 @@ static void init_currently_empty_zone(st
 {
 	const unsigned long zone_required_alignment = 1UL << (MAX_ORDER-1);
 	struct pglist_data *pgdat = zone->zone_pgdat;
-	int nid = pgdat->node_id;
 
 #ifndef CONFIG_NONLINEAR
 	/* most uses of zone->zone_mem_map can be removed */
@@ -1980,9 +1984,8 @@ static void init_currently_empty_zone(st
 	if ((zone_start_pfn) & (zone_required_alignment-1))
 		printk("BUG: wrong zone alignment, it will crash\n");
 
-	memmap_init(size, nid, zone_idx(zone), zone_start_pfn);
-
 	zone_init_free_lists(pgdat, zone, zone->spanned_pages);
+	zone->spanned_pages = size;
 
 	smp_mb();
 	pgdat->nr_zones++;
@@ -2018,7 +2021,6 @@ static void __init free_area_init_core(s
 			nr_kernel_pages += realsize;
 		nr_all_pages += realsize;
 
-		zone->spanned_pages = size;
 		zone->present_pages = realsize;
 		zone->name = zone_names[j];
 		spin_lock_init(&zone->lock);
@@ -2040,6 +2042,7 @@ static void __init free_area_init_core(s
 
 		zone_wait_table_init(zone, size);
 		init_currently_empty_zone(zone, zone_start_pfn, size);
+		memmap_init(size, nid, zone_idx(zone), zone_start_pfn);
 		zone_start_pfn += size;
 	}
 }
@@ -2600,3 +2603,31 @@ void *__init alloc_large_system_hash(con
 	return table;
 }
 
+static inline int zone_previously_initialized(struct zone *zone)
+{
+	if (zone->wait_table_size)
+		return 1;
+
+	return 0;
+}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+int  hot_add_zone_init(struct zone *zone, unsigned long phys_start_pfn, unsigned long size_pages)
+{
+	if (zone_previously_initialized(zone))
+		return -EEXIST;
+			
+	zone_wait_table_init(zone, PAGES_PER_SECTION);
+	init_currently_empty_zone(zone, phys_start_pfn, PAGES_PER_SECTION);
+	zone_pcp_init(zone);
+
+	/*
+	 * FIXME: there is no locking at all for the zonelists.
+	 * Least impactful (codewise) way to do this is probably
+	 * to freeze all the CPUs for a sec while this is done.
+	 */
+	build_zonelists(zone->zone_pgdat);
+
+	return 0;
+}
+#endif
_
