diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index ca2723d47338..b8c11e063ff0 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -1483,17 +1483,20 @@ bool is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) | |||
1483 | } | 1483 | } |
1484 | 1484 | ||
1485 | /* | 1485 | /* |
1486 | * Confirm all pages in a range [start, end) is belongs to the same zone. | 1486 | * Confirm all pages in a range [start, end) belong to the same zone. |
1487 | * When true, return its valid [start, end). | ||
1487 | */ | 1488 | */ |
1488 | int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) | 1489 | int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn, |
1490 | unsigned long *valid_start, unsigned long *valid_end) | ||
1489 | { | 1491 | { |
1490 | unsigned long pfn, sec_end_pfn; | 1492 | unsigned long pfn, sec_end_pfn; |
1493 | unsigned long start, end; | ||
1491 | struct zone *zone = NULL; | 1494 | struct zone *zone = NULL; |
1492 | struct page *page; | 1495 | struct page *page; |
1493 | int i; | 1496 | int i; |
1494 | for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn); | 1497 | for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn + 1); |
1495 | pfn < end_pfn; | 1498 | pfn < end_pfn; |
1496 | pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) { | 1499 | pfn = sec_end_pfn, sec_end_pfn += PAGES_PER_SECTION) { |
1497 | /* Make sure the memory section is present first */ | 1500 | /* Make sure the memory section is present first */ |
1498 | if (!present_section_nr(pfn_to_section_nr(pfn))) | 1501 | if (!present_section_nr(pfn_to_section_nr(pfn))) |
1499 | continue; | 1502 | continue; |
@@ -1509,10 +1512,20 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) | |||
1509 | page = pfn_to_page(pfn + i); | 1512 | page = pfn_to_page(pfn + i); |
1510 | if (zone && page_zone(page) != zone) | 1513 | if (zone && page_zone(page) != zone) |
1511 | return 0; | 1514 | return 0; |
1515 | if (!zone) | ||
1516 | start = pfn + i; | ||
1512 | zone = page_zone(page); | 1517 | zone = page_zone(page); |
1518 | end = pfn + MAX_ORDER_NR_PAGES; | ||
1513 | } | 1519 | } |
1514 | } | 1520 | } |
1515 | return 1; | 1521 | |
1522 | if (zone) { | ||
1523 | *valid_start = start; | ||
1524 | *valid_end = end; | ||
1525 | return 1; | ||
1526 | } else { | ||
1527 | return 0; | ||
1528 | } | ||
1516 | } | 1529 | } |
1517 | 1530 | ||
1518 | /* | 1531 | /* |
@@ -1839,6 +1852,7 @@ static int __ref __offline_pages(unsigned long start_pfn, | |||
1839 | long offlined_pages; | 1852 | long offlined_pages; |
1840 | int ret, drain, retry_max, node; | 1853 | int ret, drain, retry_max, node; |
1841 | unsigned long flags; | 1854 | unsigned long flags; |
1855 | unsigned long valid_start, valid_end; | ||
1842 | struct zone *zone; | 1856 | struct zone *zone; |
1843 | struct memory_notify arg; | 1857 | struct memory_notify arg; |
1844 | 1858 | ||
@@ -1849,10 +1863,10 @@ static int __ref __offline_pages(unsigned long start_pfn, | |||
1849 | return -EINVAL; | 1863 | return -EINVAL; |
1850 | /* This makes hotplug much easier...and readable. | 1864 | /* This makes hotplug much easier...and readable. |
1851 | we assume this for now. .*/ | 1865 | we assume this for now. .*/ |
1852 | if (!test_pages_in_a_zone(start_pfn, end_pfn)) | 1866 | if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end)) |
1853 | return -EINVAL; | 1867 | return -EINVAL; |
1854 | 1868 | ||
1855 | zone = page_zone(pfn_to_page(start_pfn)); | 1869 | zone = page_zone(pfn_to_page(valid_start)); |
1856 | node = zone_to_nid(zone); | 1870 | node = zone_to_nid(zone); |
1857 | nr_pages = end_pfn - start_pfn; | 1871 | nr_pages = end_pfn - start_pfn; |
1858 | 1872 | ||