diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index bb30e99b7383..1b40eebae3e4 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -813,7 +813,7 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, /* associate pfn range with the zone */ zone = zone_for_pfn_range(online_type, nid, pfn, nr_pages); - move_pfn_range_to_zone(zone, pfn, nr_pages, NULL, MIGRATE_MOVABLE); + move_pfn_range_to_zone(zone, pfn, nr_pages, NULL, MIGRATE_ISOLATE); arg.start_pfn = pfn; arg.nr_pages = nr_pages; @@ -825,6 +825,14 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, goto failed_addition; /* + * Fixup the number of isolated pageblocks before marking the sections + * onlining, such that undo_isolate_page_range() works correctly. + */ + spin_lock_irqsave(&zone->lock, flags); + zone->nr_isolate_pageblock += nr_pages / pageblock_nr_pages; + spin_unlock_irqrestore(&zone->lock, flags); + + /* * If this zone is not populated, then it is not in zonelist. * This means the page allocator ignores this zone. * So, zonelist must be updated after online. @@ -841,21 +849,25 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, zone->zone_pgdat->node_present_pages += nr_pages; pgdat_resize_unlock(zone->zone_pgdat, &flags); + node_states_set_node(nid, &arg); + if (need_zonelists_rebuild) + build_all_zonelists(NULL); + zone_pcp_update(zone); + + /* Basic onlining is complete, allow allocation of onlined pages. */ + undo_isolate_page_range(pfn, pfn + nr_pages, MIGRATE_MOVABLE); + /* * When exposing larger, physically contiguous memory areas to the * buddy, shuffling in the buddy (when freeing onlined pages, putting * them either to the head or the tail of the freelist) is only helpful * for maintaining the shuffle, but not for creating the initial * shuffle. Shuffle the whole zone to make sure the just onlined pages - * are properly distributed across the whole freelist. + * are properly distributed across the whole freelist. Make sure to + * shuffle once pageblocks are no longer isolated. */ shuffle_zone(zone); - node_states_set_node(nid, &arg); - if (need_zonelists_rebuild) - build_all_zonelists(NULL); - zone_pcp_update(zone); - init_per_zone_wmark_min(); kswapd_run(nid); @@ -1577,9 +1589,9 @@ int __ref offline_pages(unsigned long start_pfn, unsigned long nr_pages) pr_info("Offlined Pages %ld\n", nr_pages); /* - * Onlining will reset pagetype flags and makes migrate type - * MOVABLE, so just need to decrease the number of isolated - * pageblocks zone counter here. + * The memory sections are marked offline, and the pageblock flags + * effectively stale; nobody should be touching them. Fixup the number + * of isolated pageblocks, memory onlining will properly revert this. */ spin_lock_irqsave(&zone->lock, flags); zone->nr_isolate_pageblock -= nr_pages / pageblock_nr_pages; |