summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArun KS <arunks@codeaurora.org>2019-03-05 18:42:14 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-06 00:07:14 -0500
commita9cd410a3d296846a8125aa43d97a573a354c472 (patch)
treee595bcf29faa43aefe2fd0962e11a3a8d8f0c9e2
parent278d7756dff0b4c8089c46abad20a79bcfa66b5b (diff)
mm/page_alloc.c: memory hotplug: free pages as higher order
When freeing pages are done with higher order, time spent on coalescing pages by buddy allocator can be reduced. With section size of 256MB, hot add latency of a single section shows improvement from 50-60 ms to less than 1 ms, hence improving the hot add latency by 60 times. Modify external providers of online callback to align with the change. [arunks@codeaurora.org: v11] Link: http://lkml.kernel.org/r/1547792588-18032-1-git-send-email-arunks@codeaurora.org [akpm@linux-foundation.org: remove unused local, per Arun] [akpm@linux-foundation.org: avoid return of void-returning __free_pages_core(), per Oscar] [akpm@linux-foundation.org: fix it for mm-convert-totalram_pages-and-totalhigh_pages-variables-to-atomic.patch] [arunks@codeaurora.org: v8] Link: http://lkml.kernel.org/r/1547032395-24582-1-git-send-email-arunks@codeaurora.org [arunks@codeaurora.org: v9] Link: http://lkml.kernel.org/r/1547098543-26452-1-git-send-email-arunks@codeaurora.org Link: http://lkml.kernel.org/r/1538727006-5727-1-git-send-email-arunks@codeaurora.org Signed-off-by: Arun KS <arunks@codeaurora.org> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: Michal Hocko <mhocko@suse.com> Reviewed-by: Oscar Salvador <osalvador@suse.de> Reviewed-by: Alexander Duyck <alexander.h.duyck@linux.intel.com> Cc: K. Y. Srinivasan <kys@microsoft.com> Cc: Haiyang Zhang <haiyangz@microsoft.com> Cc: Stephen Hemminger <sthemmin@microsoft.com> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Juergen Gross <jgross@suse.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Mathieu Malaterre <malat@debian.org> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Souptick Joarder <jrdr.linux@gmail.com> Cc: Mel Gorman <mgorman@techsingularity.net> Cc: Aaron Lu <aaron.lu@intel.com> Cc: Srivatsa Vaddagiri <vatsa@codeaurora.org> Cc: Vinayak Menon <vinmenon@codeaurora.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/hv/hv_balloon.c7
-rw-r--r--drivers/xen/balloon.c15
-rw-r--r--include/linux/memory_hotplug.h2
-rw-r--r--mm/internal.h1
-rw-r--r--mm/memory_hotplug.c37
-rw-r--r--mm/page_alloc.c8
6 files changed, 45 insertions, 25 deletions
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 7c6349a50ef1..a50b7624b2a3 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -771,7 +771,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
771 } 771 }
772} 772}
773 773
774static void hv_online_page(struct page *pg) 774static void hv_online_page(struct page *pg, unsigned int order)
775{ 775{
776 struct hv_hotadd_state *has; 776 struct hv_hotadd_state *has;
777 unsigned long flags; 777 unsigned long flags;
@@ -780,10 +780,11 @@ static void hv_online_page(struct page *pg)
780 spin_lock_irqsave(&dm_device.ha_lock, flags); 780 spin_lock_irqsave(&dm_device.ha_lock, flags);
781 list_for_each_entry(has, &dm_device.ha_region_list, list) { 781 list_for_each_entry(has, &dm_device.ha_region_list, list) {
782 /* The page belongs to a different HAS. */ 782 /* The page belongs to a different HAS. */
783 if ((pfn < has->start_pfn) || (pfn >= has->end_pfn)) 783 if ((pfn < has->start_pfn) ||
784 (pfn + (1UL << order) > has->end_pfn))
784 continue; 785 continue;
785 786
786 hv_page_online_one(has, pg); 787 hv_bring_pgs_online(has, pfn, 1UL << order);
787 break; 788 break;
788 } 789 }
789 spin_unlock_irqrestore(&dm_device.ha_lock, flags); 790 spin_unlock_irqrestore(&dm_device.ha_lock, flags);
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index ceb5048de9a7..d107447c47de 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -369,14 +369,19 @@ static enum bp_state reserve_additional_memory(void)
369 return BP_ECANCELED; 369 return BP_ECANCELED;
370} 370}
371 371
372static void xen_online_page(struct page *page) 372static void xen_online_page(struct page *page, unsigned int order)
373{ 373{
374 __online_page_set_limits(page); 374 unsigned long i, size = (1 << order);
375 unsigned long start_pfn = page_to_pfn(page);
376 struct page *p;
375 377
378 pr_debug("Online %lu pages starting at pfn 0x%lx\n", size, start_pfn);
376 mutex_lock(&balloon_mutex); 379 mutex_lock(&balloon_mutex);
377 380 for (i = 0; i < size; i++) {
378 __balloon_append(page); 381 p = pfn_to_page(start_pfn + i);
379 382 __online_page_set_limits(p);
383 __balloon_append(p);
384 }
380 mutex_unlock(&balloon_mutex); 385 mutex_unlock(&balloon_mutex);
381} 386}
382 387
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 368267c1b71b..52869d6d38b3 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -89,7 +89,7 @@ extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
89 unsigned long *valid_start, unsigned long *valid_end); 89 unsigned long *valid_start, unsigned long *valid_end);
90extern void __offline_isolated_pages(unsigned long, unsigned long); 90extern void __offline_isolated_pages(unsigned long, unsigned long);
91 91
92typedef void (*online_page_callback_t)(struct page *page); 92typedef void (*online_page_callback_t)(struct page *page, unsigned int order);
93 93
94extern int set_online_page_callback(online_page_callback_t callback); 94extern int set_online_page_callback(online_page_callback_t callback);
95extern int restore_online_page_callback(online_page_callback_t callback); 95extern int restore_online_page_callback(online_page_callback_t callback);
diff --git a/mm/internal.h b/mm/internal.h
index f4a7bb02decf..536bc2a839b9 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -163,6 +163,7 @@ static inline struct page *pageblock_pfn_to_page(unsigned long start_pfn,
163extern int __isolate_free_page(struct page *page, unsigned int order); 163extern int __isolate_free_page(struct page *page, unsigned int order);
164extern void memblock_free_pages(struct page *page, unsigned long pfn, 164extern void memblock_free_pages(struct page *page, unsigned long pfn,
165 unsigned int order); 165 unsigned int order);
166extern void __free_pages_core(struct page *page, unsigned int order);
166extern void prep_compound_page(struct page *page, unsigned int order); 167extern void prep_compound_page(struct page *page, unsigned int order);
167extern void post_alloc_hook(struct page *page, unsigned int order, 168extern void post_alloc_hook(struct page *page, unsigned int order,
168 gfp_t gfp_flags); 169 gfp_t gfp_flags);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 1ad28323fb9f..4f07c8ddfdd7 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -47,7 +47,7 @@
47 * and restore_online_page_callback() for generic callback restore. 47 * and restore_online_page_callback() for generic callback restore.
48 */ 48 */
49 49
50static void generic_online_page(struct page *page); 50static void generic_online_page(struct page *page, unsigned int order);
51 51
52static online_page_callback_t online_page_callback = generic_online_page; 52static online_page_callback_t online_page_callback = generic_online_page;
53static DEFINE_MUTEX(online_page_callback_lock); 53static DEFINE_MUTEX(online_page_callback_lock);
@@ -656,26 +656,39 @@ void __online_page_free(struct page *page)
656} 656}
657EXPORT_SYMBOL_GPL(__online_page_free); 657EXPORT_SYMBOL_GPL(__online_page_free);
658 658
659static void generic_online_page(struct page *page) 659static void generic_online_page(struct page *page, unsigned int order)
660{ 660{
661 __online_page_set_limits(page); 661 __free_pages_core(page, order);
662 __online_page_increment_counters(page); 662 totalram_pages_add(1UL << order);
663 __online_page_free(page); 663#ifdef CONFIG_HIGHMEM
664 if (PageHighMem(page))
665 totalhigh_pages_add(1UL << order);
666#endif
667}
668
669static int online_pages_blocks(unsigned long start, unsigned long nr_pages)
670{
671 unsigned long end = start + nr_pages;
672 int order, onlined_pages = 0;
673
674 while (start < end) {
675 order = min(MAX_ORDER - 1,
676 get_order(PFN_PHYS(end) - PFN_PHYS(start)));
677 (*online_page_callback)(pfn_to_page(start), order);
678
679 onlined_pages += (1UL << order);
680 start += (1UL << order);
681 }
682 return onlined_pages;
664} 683}
665 684
666static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, 685static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
667 void *arg) 686 void *arg)
668{ 687{
669 unsigned long i;
670 unsigned long onlined_pages = *(unsigned long *)arg; 688 unsigned long onlined_pages = *(unsigned long *)arg;
671 struct page *page;
672 689
673 if (PageReserved(pfn_to_page(start_pfn))) 690 if (PageReserved(pfn_to_page(start_pfn)))
674 for (i = 0; i < nr_pages; i++) { 691 onlined_pages += online_pages_blocks(start_pfn, nr_pages);
675 page = pfn_to_page(start_pfn + i);
676 (*online_page_callback)(page);
677 onlined_pages++;
678 }
679 692
680 online_mem_sections(start_pfn, start_pfn + nr_pages); 693 online_mem_sections(start_pfn, start_pfn + nr_pages);
681 694
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 10d0f2ed9f69..5361bd078493 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1303,7 +1303,7 @@ static void __free_pages_ok(struct page *page, unsigned int order)
1303 local_irq_restore(flags); 1303 local_irq_restore(flags);
1304} 1304}
1305 1305
1306static void __init __free_pages_boot_core(struct page *page, unsigned int order) 1306void __free_pages_core(struct page *page, unsigned int order)
1307{ 1307{
1308 unsigned int nr_pages = 1 << order; 1308 unsigned int nr_pages = 1 << order;
1309 struct page *p = page; 1309 struct page *p = page;
@@ -1382,7 +1382,7 @@ void __init memblock_free_pages(struct page *page, unsigned long pfn,
1382{ 1382{
1383 if (early_page_uninitialised(pfn)) 1383 if (early_page_uninitialised(pfn))
1384 return; 1384 return;
1385 return __free_pages_boot_core(page, order); 1385 __free_pages_core(page, order);
1386} 1386}
1387 1387
1388/* 1388/*
@@ -1472,14 +1472,14 @@ static void __init deferred_free_range(unsigned long pfn,
1472 if (nr_pages == pageblock_nr_pages && 1472 if (nr_pages == pageblock_nr_pages &&
1473 (pfn & (pageblock_nr_pages - 1)) == 0) { 1473 (pfn & (pageblock_nr_pages - 1)) == 0) {
1474 set_pageblock_migratetype(page, MIGRATE_MOVABLE); 1474 set_pageblock_migratetype(page, MIGRATE_MOVABLE);
1475 __free_pages_boot_core(page, pageblock_order); 1475 __free_pages_core(page, pageblock_order);
1476 return; 1476 return;
1477 } 1477 }
1478 1478
1479 for (i = 0; i < nr_pages; i++, page++, pfn++) { 1479 for (i = 0; i < nr_pages; i++, page++, pfn++) {
1480 if ((pfn & (pageblock_nr_pages - 1)) == 0) 1480 if ((pfn & (pageblock_nr_pages - 1)) == 0)
1481 set_pageblock_migratetype(page, MIGRATE_MOVABLE); 1481 set_pageblock_migratetype(page, MIGRATE_MOVABLE);
1482 __free_pages_boot_core(page, 0); 1482 __free_pages_core(page, 0);
1483 } 1483 }
1484} 1484}
1485 1485