If any page is still online, the section should stay online. Signed-off-by: David Hildenbrand <david@xxxxxxxxxx> --- mm/page_alloc.c | 2 +- mm/sparse.c | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 2e5dcfdb0908..ae9023da2ca2 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -8013,7 +8013,6 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn) break; if (pfn == end_pfn) return; - offline_mem_sections(pfn, end_pfn); zone = page_zone(pfn_to_page(pfn)); spin_lock_irqsave(&zone->lock, flags); pfn = start_pfn; @@ -8051,6 +8050,7 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn) pfn += (1 << order); } spin_unlock_irqrestore(&zone->lock, flags); + offline_mem_sections(start_pfn, end_pfn); } #endif diff --git a/mm/sparse.c b/mm/sparse.c index 58cab483e81b..44978cb18fed 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -623,7 +623,27 @@ void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn) } #ifdef CONFIG_MEMORY_HOTREMOVE -/* Mark all memory sections within the pfn range as online */ +static bool all_pages_in_section_offline(unsigned long section_nr) +{ + unsigned long pfn = section_nr_to_pfn(section_nr); + struct page *page; + int i; + + for (i = 0; i < PAGES_PER_SECTION; i++, pfn++) { + if (!pfn_valid(pfn)) + continue; + + page = pfn_to_page(pfn); + if (!PageOffline(page)) + return false; + } + return true; +} + +/* + * Mark all memory sections within the pfn range as offline (if all pages + * of a memory section are already offline) + */ void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn) { unsigned long pfn; @@ -639,6 +659,9 @@ void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn) if (WARN_ON(!valid_section_nr(section_nr))) continue; + if (!all_pages_in_section_offline(section_nr)) + continue; + ms = __nr_to_section(section_nr); ms->section_mem_map &= ~SECTION_IS_ONLINE; } -- 2.14.3