diff --git a/mm/memblock.c b/mm/memblock.c
index 1018e50566f3..6dfa594192de 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1400,6 +1400,7 @@ phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
*/
kmemleak_alloc_phys(found, size, 0, 0);
+ accept_memory(found, found + size);
return found;
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c5952749ad40..5707b4b5f774 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1064,6 +1064,7 @@ static inline void __free_one_page(struct page *page,
unsigned int max_order;
struct page *buddy;
bool to_tail;
+ bool offline = PageOffline(page);
max_order = min_t(unsigned int, MAX_ORDER - 1, pageblock_order);
@@ -1097,6 +1098,10 @@ static inline void __free_one_page(struct page *page,
clear_page_guard(zone, buddy, order, migratetype);
else
del_page_from_free_list(buddy, zone, order);
+
+ if (PageOffline(buddy))
+ offline = true;
+
combined_pfn = buddy_pfn & pfn;
page = page + (combined_pfn - pfn);
pfn = combined_pfn;
@@ -1130,6 +1135,9 @@ static inline void __free_one_page(struct page *page,
done_merging:
set_buddy_order(page, order);
+ if (offline)
+ __SetPageOffline(page);
+
if (fpi_flags & FPI_TO_TAIL)
to_tail = true;
else if (is_shuffle_order(order))
@@ -1155,7 +1163,8 @@ static inline void __free_one_page(struct page *page,
static inline bool page_expected_state(struct page *page,
unsigned long check_flags)
{
- if (unlikely(atomic_read(&page->_mapcount) != -1))
+ if (unlikely(atomic_read(&page->_mapcount) != -1) &&
+ !PageOffline(page))
return false;
if (unlikely((unsigned long)page->mapping |
@@ -1734,6 +1743,8 @@ void __init memblock_free_pages(struct page *page, unsigned long pfn,
{
if (early_page_uninitialised(pfn))
return;
+
+ maybe_set_page_offline(page, order);
__free_pages_core(page, order);
}
@@ -1823,10 +1834,12 @@ static void __init deferred_free_range(unsigned long pfn,
if (nr_pages == pageblock_nr_pages &&
(pfn & (pageblock_nr_pages - 1)) == 0) {
set_pageblock_migratetype(page, MIGRATE_MOVABLE);
+ maybe_set_page_offline(page, pageblock_order);
__free_pages_core(page, pageblock_order);
return;
}
+ accept_memory(pfn << PAGE_SHIFT, (pfn + nr_pages) << PAGE_SHIFT);
for (i = 0; i < nr_pages; i++, page++, pfn++) {
if ((pfn & (pageblock_nr_pages - 1)) == 0)
set_pageblock_migratetype(page, MIGRATE_MOVABLE);
@@ -2297,6 +2310,9 @@ static inline void expand(struct zone *zone, struct page *page,
if (set_page_guard(zone, &page[size], high, migratetype))
continue;
+ if (PageOffline(page))
+ __SetPageOffline(&page[size]);
add_to_free_list(&page[size], zone, high, migratetype);
set_buddy_order(&page[size], high);
}
@@ -2393,6 +2409,9 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
*/
kernel_unpoison_pages(page, 1 << order);
+ if (PageOffline(page))
+ accept_and_clear_page_offline(page, order);
+
/*
* As memory initialization might be integrated into KASAN,
* kasan_alloc_pages and kernel_init_free_pages must be