Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[deliverable/linux.git] / mm / memory_hotplug.c
index e189b1f4a9dbd36d5cee5cbf609af99e45ea8db5..b81a367b9f39bb056cc4127a674e8a3dd4d2567d 100644 (file)
@@ -124,6 +124,7 @@ void __ref put_page_bootmem(struct page *page)
                mutex_lock(&ppb_lock);
                __free_pages_bootmem(page, 0);
                mutex_unlock(&ppb_lock);
+               totalram_pages++;
        }
 
 }
@@ -217,7 +218,7 @@ void register_page_bootmem_info_node(struct pglist_data *pgdat)
        }
 
        pfn = pgdat->node_start_pfn;
-       end_pfn = pfn + pgdat->node_spanned_pages;
+       end_pfn = pgdat_end_pfn(pgdat);
 
        /* register_section info */
        for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
@@ -281,6 +282,17 @@ static void fix_zone_id(struct zone *zone, unsigned long start_pfn,
                set_page_links(pfn_to_page(pfn), zid, nid, pfn);
 }
 
+/* Can fail with -ENOMEM from allocating a wait table with vmalloc() or
+ * alloc_bootmem_node_nopanic() */
+static int __ref ensure_zone_is_initialized(struct zone *zone,
+                       unsigned long start_pfn, unsigned long num_pages)
+{
+       if (!zone_is_initialized(zone))
+               return init_currently_empty_zone(zone, start_pfn, num_pages,
+                                                MEMMAP_HOTPLUG);
+       return 0;
+}
+
 static int __meminit move_pfn_range_left(struct zone *z1, struct zone *z2,
                unsigned long start_pfn, unsigned long end_pfn)
 {
@@ -288,17 +300,14 @@ static int __meminit move_pfn_range_left(struct zone *z1, struct zone *z2,
        unsigned long flags;
        unsigned long z1_start_pfn;
 
-       if (!z1->wait_table) {
-               ret = init_currently_empty_zone(z1, start_pfn,
-                       end_pfn - start_pfn, MEMMAP_HOTPLUG);
-               if (ret)
-                       return ret;
-       }
+       ret = ensure_zone_is_initialized(z1, start_pfn, end_pfn - start_pfn);
+       if (ret)
+               return ret;
 
        pgdat_resize_lock(z1->zone_pgdat, &flags);
 
        /* can't move pfns which are higher than @z2 */
-       if (end_pfn > z2->zone_start_pfn + z2->spanned_pages)
+       if (end_pfn > zone_end_pfn(z2))
                goto out_fail;
        /* the move out part mast at the left most of @z2 */
        if (start_pfn > z2->zone_start_pfn)
@@ -314,7 +323,7 @@ static int __meminit move_pfn_range_left(struct zone *z1, struct zone *z2,
                z1_start_pfn = start_pfn;
 
        resize_zone(z1, z1_start_pfn, end_pfn);
-       resize_zone(z2, end_pfn, z2->zone_start_pfn + z2->spanned_pages);
+       resize_zone(z2, end_pfn, zone_end_pfn(z2));
 
        pgdat_resize_unlock(z1->zone_pgdat, &flags);
 
@@ -333,12 +342,9 @@ static int __meminit move_pfn_range_right(struct zone *z1, struct zone *z2,
        unsigned long flags;
        unsigned long z2_end_pfn;
 
-       if (!z2->wait_table) {
-               ret = init_currently_empty_zone(z2, start_pfn,
-                       end_pfn - start_pfn, MEMMAP_HOTPLUG);
-               if (ret)
-                       return ret;
-       }
+       ret = ensure_zone_is_initialized(z2, start_pfn, end_pfn - start_pfn);
+       if (ret)
+               return ret;
 
        pgdat_resize_lock(z1->zone_pgdat, &flags);
 
@@ -346,15 +352,15 @@ static int __meminit move_pfn_range_right(struct zone *z1, struct zone *z2,
        if (z1->zone_start_pfn > start_pfn)
                goto out_fail;
        /* the move out part mast at the right most of @z1 */
-       if (z1->zone_start_pfn + z1->spanned_pages >  end_pfn)
+       if (zone_end_pfn(z1) >  end_pfn)
                goto out_fail;
        /* must included/overlap */
-       if (start_pfn >= z1->zone_start_pfn + z1->spanned_pages)
+       if (start_pfn >= zone_end_pfn(z1))
                goto out_fail;
 
        /* use end_pfn for z2's end_pfn if z2 is empty */
        if (z2->spanned_pages)
-               z2_end_pfn = z2->zone_start_pfn + z2->spanned_pages;
+               z2_end_pfn = zone_end_pfn(z2);
        else
                z2_end_pfn = end_pfn;
 
@@ -391,16 +397,13 @@ static int __meminit __add_zone(struct zone *zone, unsigned long phys_start_pfn)
        int nid = pgdat->node_id;
        int zone_type;
        unsigned long flags;
+       int ret;
 
        zone_type = zone - pgdat->node_zones;
-       if (!zone->wait_table) {
-               int ret;
+       ret = ensure_zone_is_initialized(zone, phys_start_pfn, nr_pages);
+       if (ret)
+               return ret;
 
-               ret = init_currently_empty_zone(zone, phys_start_pfn,
-                                               nr_pages, MEMMAP_HOTPLUG);
-               if (ret)
-                       return ret;
-       }
        pgdat_resize_lock(zone->zone_pgdat, &flags);
        grow_zone_span(zone, phys_start_pfn, phys_start_pfn + nr_pages);
        grow_pgdat_span(zone->zone_pgdat, phys_start_pfn,
@@ -1285,8 +1288,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                 * migrate_pages returns # of failed pages.
                 */
                ret = migrate_pages(&source, alloc_migrate_target, 0,
-                                                       true, MIGRATE_SYNC,
-                                                       MR_MEMORY_HOTPLUG);
+                                       MIGRATE_SYNC, MR_MEMORY_HOTPLUG);
                if (ret)
                        putback_lru_pages(&source);
        }
@@ -1705,8 +1707,36 @@ static int check_cpu_on_node(void *data)
        return 0;
 }
 
+static void unmap_cpu_on_node(void *data)
+{
+#ifdef CONFIG_ACPI_NUMA
+       struct pglist_data *pgdat = data;
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               if (cpu_to_node(cpu) == pgdat->node_id)
+                       numa_clear_node(cpu);
+#endif
+}
+
+static int check_and_unmap_cpu_on_node(void *data)
+{
+       int ret = check_cpu_on_node(data);
+
+       if (ret)
+               return ret;
+
+       /*
+        * the node will be offlined when we come here, so we can clear
+        * the cpu_to_node() now.
+        */
+
+       unmap_cpu_on_node(data);
+       return 0;
+}
+
 /* offline the node if all memory sections of this node are removed */
-static void try_offline_node(int nid)
+void try_offline_node(int nid)
 {
        pg_data_t *pgdat = NODE_DATA(nid);
        unsigned long start_pfn = pgdat->node_start_pfn;
@@ -1731,7 +1761,7 @@ static void try_offline_node(int nid)
                return;
        }
 
-       if (stop_machine(check_cpu_on_node, pgdat, NULL))
+       if (stop_machine(check_and_unmap_cpu_on_node, pgdat, NULL))
                return;
 
        /*
@@ -1762,6 +1792,7 @@ static void try_offline_node(int nid)
         */
        memset(pgdat, 0, sizeof(*pgdat));
 }
+EXPORT_SYMBOL(try_offline_node);
 
 int __ref remove_memory(int nid, u64 start, u64 size)
 {
This page took 0.041662 seconds and 5 git commands to generate.