diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 28 |
1 files changed, 17 insertions, 11 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index e43142c15631..ca2723d47338 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -1033,36 +1033,39 @@ static void node_states_set_node(int node, struct memory_notify *arg) | |||
1033 | node_set_state(node, N_MEMORY); | 1033 | node_set_state(node, N_MEMORY); |
1034 | } | 1034 | } |
1035 | 1035 | ||
1036 | int zone_can_shift(unsigned long pfn, unsigned long nr_pages, | 1036 | bool zone_can_shift(unsigned long pfn, unsigned long nr_pages, |
1037 | enum zone_type target) | 1037 | enum zone_type target, int *zone_shift) |
1038 | { | 1038 | { |
1039 | struct zone *zone = page_zone(pfn_to_page(pfn)); | 1039 | struct zone *zone = page_zone(pfn_to_page(pfn)); |
1040 | enum zone_type idx = zone_idx(zone); | 1040 | enum zone_type idx = zone_idx(zone); |
1041 | int i; | 1041 | int i; |
1042 | 1042 | ||
1043 | *zone_shift = 0; | ||
1044 | |||
1043 | if (idx < target) { | 1045 | if (idx < target) { |
1044 | /* pages must be at end of current zone */ | 1046 | /* pages must be at end of current zone */ |
1045 | if (pfn + nr_pages != zone_end_pfn(zone)) | 1047 | if (pfn + nr_pages != zone_end_pfn(zone)) |
1046 | return 0; | 1048 | return false; |
1047 | 1049 | ||
1048 | /* no zones in use between current zone and target */ | 1050 | /* no zones in use between current zone and target */ |
1049 | for (i = idx + 1; i < target; i++) | 1051 | for (i = idx + 1; i < target; i++) |
1050 | if (zone_is_initialized(zone - idx + i)) | 1052 | if (zone_is_initialized(zone - idx + i)) |
1051 | return 0; | 1053 | return false; |
1052 | } | 1054 | } |
1053 | 1055 | ||
1054 | if (target < idx) { | 1056 | if (target < idx) { |
1055 | /* pages must be at beginning of current zone */ | 1057 | /* pages must be at beginning of current zone */ |
1056 | if (pfn != zone->zone_start_pfn) | 1058 | if (pfn != zone->zone_start_pfn) |
1057 | return 0; | 1059 | return false; |
1058 | 1060 | ||
1059 | /* no zones in use between current zone and target */ | 1061 | /* no zones in use between current zone and target */ |
1060 | for (i = target + 1; i < idx; i++) | 1062 | for (i = target + 1; i < idx; i++) |
1061 | if (zone_is_initialized(zone - idx + i)) | 1063 | if (zone_is_initialized(zone - idx + i)) |
1062 | return 0; | 1064 | return false; |
1063 | } | 1065 | } |
1064 | 1066 | ||
1065 | return target - idx; | 1067 | *zone_shift = target - idx; |
1068 | return true; | ||
1066 | } | 1069 | } |
1067 | 1070 | ||
1068 | /* Must be protected by mem_hotplug_begin() */ | 1071 | /* Must be protected by mem_hotplug_begin() */ |
@@ -1089,10 +1092,13 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ | |||
1089 | !can_online_high_movable(zone)) | 1092 | !can_online_high_movable(zone)) |
1090 | return -EINVAL; | 1093 | return -EINVAL; |
1091 | 1094 | ||
1092 | if (online_type == MMOP_ONLINE_KERNEL) | 1095 | if (online_type == MMOP_ONLINE_KERNEL) { |
1093 | zone_shift = zone_can_shift(pfn, nr_pages, ZONE_NORMAL); | 1096 | if (!zone_can_shift(pfn, nr_pages, ZONE_NORMAL, &zone_shift)) |
1094 | else if (online_type == MMOP_ONLINE_MOVABLE) | 1097 | return -EINVAL; |
1095 | zone_shift = zone_can_shift(pfn, nr_pages, ZONE_MOVABLE); | 1098 | } else if (online_type == MMOP_ONLINE_MOVABLE) { |
1099 | if (!zone_can_shift(pfn, nr_pages, ZONE_MOVABLE, &zone_shift)) | ||
1100 | return -EINVAL; | ||
1101 | } | ||
1096 | 1102 | ||
1097 | zone = move_pfn_range(zone_shift, pfn, pfn + nr_pages); | 1103 | zone = move_pfn_range(zone_shift, pfn, pfn + nr_pages); |
1098 | if (!zone) | 1104 | if (!zone) |