|
@@ -1484,10 +1484,13 @@ bool is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
|
|
|
|
|
|
/*
|
|
|
* Confirm all pages in a range [start, end) belong to the same zone.
|
|
|
+ * When true, return its valid [start, end).
|
|
|
*/
|
|
|
-int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
|
|
|
+int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
|
|
|
+ unsigned long *valid_start, unsigned long *valid_end)
|
|
|
{
|
|
|
unsigned long pfn, sec_end_pfn;
|
|
|
+ unsigned long start, end;
|
|
|
struct zone *zone = NULL;
|
|
|
struct page *page;
|
|
|
int i;
|
|
@@ -1509,14 +1512,20 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
|
|
|
page = pfn_to_page(pfn + i);
|
|
|
if (zone && page_zone(page) != zone)
|
|
|
return 0;
|
|
|
+ if (!zone)
|
|
|
+ start = pfn + i;
|
|
|
zone = page_zone(page);
|
|
|
+ end = pfn + MAX_ORDER_NR_PAGES;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (zone)
|
|
|
+ if (zone) {
|
|
|
+ *valid_start = start;
|
|
|
+ *valid_end = end;
|
|
|
return 1;
|
|
|
- else
|
|
|
+ } else {
|
|
|
return 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1843,6 +1852,7 @@ static int __ref __offline_pages(unsigned long start_pfn,
|
|
|
long offlined_pages;
|
|
|
int ret, drain, retry_max, node;
|
|
|
unsigned long flags;
|
|
|
+ unsigned long valid_start, valid_end;
|
|
|
struct zone *zone;
|
|
|
struct memory_notify arg;
|
|
|
|
|
@@ -1853,10 +1863,10 @@ static int __ref __offline_pages(unsigned long start_pfn,
|
|
|
return -EINVAL;
|
|
|
/* This makes hotplug much easier...and readable.
|
|
|
we assume this for now. .*/
|
|
|
- if (!test_pages_in_a_zone(start_pfn, end_pfn))
|
|
|
+ if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- zone = page_zone(pfn_to_page(start_pfn));
|
|
|
+ zone = page_zone(pfn_to_page(valid_start));
|
|
|
node = zone_to_nid(zone);
|
|
|
nr_pages = end_pfn - start_pfn;
|
|
|
|