|
@@ -1047,6 +1047,37 @@ static void node_states_set_node(int node, struct memory_notify *arg)
|
|
|
node_set_state(node, N_MEMORY);
|
|
|
}
|
|
|
|
|
|
+int zone_can_shift(unsigned long pfn, unsigned long nr_pages,
|
|
|
+ enum zone_type target)
|
|
|
+{
|
|
|
+ struct zone *zone = page_zone(pfn_to_page(pfn));
|
|
|
+ enum zone_type idx = zone_idx(zone);
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (idx < target) {
|
|
|
+ /* pages must be at end of current zone */
|
|
|
+ if (pfn + nr_pages != zone_end_pfn(zone))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* no zones in use between current zone and target */
|
|
|
+ for (i = idx + 1; i < target; i++)
|
|
|
+ if (zone_is_initialized(zone - idx + i))
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (target < idx) {
|
|
|
+ /* pages must be at beginning of current zone */
|
|
|
+ if (pfn != zone->zone_start_pfn)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* no zones in use between current zone and target */
|
|
|
+ for (i = target + 1; i < idx; i++)
|
|
|
+ if (zone_is_initialized(zone - idx + i))
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return target - idx;
|
|
|
+}
|
|
|
|
|
|
/* Must be protected by mem_hotplug_begin() */
|
|
|
int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_type)
|
|
@@ -1072,13 +1103,10 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
|
|
|
!can_online_high_movable(zone))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (online_type == MMOP_ONLINE_KERNEL &&
|
|
|
- zone_idx(zone) == ZONE_MOVABLE)
|
|
|
- zone_shift = -1;
|
|
|
-
|
|
|
- if (online_type == MMOP_ONLINE_MOVABLE &&
|
|
|
- zone_idx(zone) == ZONE_MOVABLE - 1)
|
|
|
- zone_shift = 1;
|
|
|
+ if (online_type == MMOP_ONLINE_KERNEL)
|
|
|
+ zone_shift = zone_can_shift(pfn, nr_pages, ZONE_NORMAL);
|
|
|
+ else if (online_type == MMOP_ONLINE_MOVABLE)
|
|
|
+ zone_shift = zone_can_shift(pfn, nr_pages, ZONE_MOVABLE);
|
|
|
|
|
|
zone = move_pfn_range(zone_shift, pfn, pfn + nr_pages);
|
|
|
if (!zone)
|