|
@@ -449,6 +449,25 @@ out_fail:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+static struct zone * __meminit move_pfn_range(int zone_shift,
|
|
|
+ unsigned long start_pfn, unsigned long end_pfn)
|
|
|
+{
|
|
|
+ struct zone *zone = page_zone(pfn_to_page(start_pfn));
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (zone_shift < 0)
|
|
|
+ ret = move_pfn_range_left(zone + zone_shift, zone,
|
|
|
+ start_pfn, end_pfn);
|
|
|
+ else if (zone_shift)
|
|
|
+ ret = move_pfn_range_right(zone, zone + zone_shift,
|
|
|
+ start_pfn, end_pfn);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return zone + zone_shift;
|
|
|
+}
|
|
|
+
|
|
|
static void __meminit grow_pgdat_span(struct pglist_data *pgdat, unsigned long start_pfn,
|
|
|
unsigned long end_pfn)
|
|
|
{
|
|
@@ -1039,6 +1058,7 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
|
|
|
int nid;
|
|
|
int ret;
|
|
|
struct memory_notify arg;
|
|
|
+ int zone_shift = 0;
|
|
|
|
|
|
/*
|
|
|
* This doesn't need a lock to do pfn_to_page().
|
|
@@ -1053,18 +1073,16 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (online_type == MMOP_ONLINE_KERNEL &&
|
|
|
- zone_idx(zone) == ZONE_MOVABLE) {
|
|
|
- if (move_pfn_range_left(zone - 1, zone, pfn, pfn + nr_pages))
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ zone_idx(zone) == ZONE_MOVABLE)
|
|
|
+ zone_shift = -1;
|
|
|
+
|
|
|
if (online_type == MMOP_ONLINE_MOVABLE &&
|
|
|
- zone_idx(zone) == ZONE_MOVABLE - 1) {
|
|
|
- if (move_pfn_range_right(zone, zone + 1, pfn, pfn + nr_pages))
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ zone_idx(zone) == ZONE_MOVABLE - 1)
|
|
|
+ zone_shift = 1;
|
|
|
|
|
|
- /* Previous code may changed the zone of the pfn range */
|
|
|
- zone = page_zone(pfn_to_page(pfn));
|
|
|
+ zone = move_pfn_range(zone_shift, pfn, pfn + nr_pages);
|
|
|
+ if (!zone)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
arg.start_pfn = pfn;
|
|
|
arg.nr_pages = nr_pages;
|