diff options
-rw-r--r-- | drivers/hv/hv_balloon.c | 7 | ||||
-rw-r--r-- | drivers/xen/balloon.c | 15 | ||||
-rw-r--r-- | include/linux/memory_hotplug.h | 2 | ||||
-rw-r--r-- | mm/internal.h | 1 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 37 | ||||
-rw-r--r-- | mm/page_alloc.c | 8 |
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 | ||
774 | static void hv_online_page(struct page *pg) | 774 | static 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 | ||
372 | static void xen_online_page(struct page *page) | 372 | static 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); |
90 | extern void __offline_isolated_pages(unsigned long, unsigned long); | 90 | extern void __offline_isolated_pages(unsigned long, unsigned long); |
91 | 91 | ||
92 | typedef void (*online_page_callback_t)(struct page *page); | 92 | typedef void (*online_page_callback_t)(struct page *page, unsigned int order); |
93 | 93 | ||
94 | extern int set_online_page_callback(online_page_callback_t callback); | 94 | extern int set_online_page_callback(online_page_callback_t callback); |
95 | extern int restore_online_page_callback(online_page_callback_t callback); | 95 | extern 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, | |||
163 | extern int __isolate_free_page(struct page *page, unsigned int order); | 163 | extern int __isolate_free_page(struct page *page, unsigned int order); |
164 | extern void memblock_free_pages(struct page *page, unsigned long pfn, | 164 | extern void memblock_free_pages(struct page *page, unsigned long pfn, |
165 | unsigned int order); | 165 | unsigned int order); |
166 | extern void __free_pages_core(struct page *page, unsigned int order); | ||
166 | extern void prep_compound_page(struct page *page, unsigned int order); | 167 | extern void prep_compound_page(struct page *page, unsigned int order); |
167 | extern void post_alloc_hook(struct page *page, unsigned int order, | 168 | extern 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 | ||
50 | static void generic_online_page(struct page *page); | 50 | static void generic_online_page(struct page *page, unsigned int order); |
51 | 51 | ||
52 | static online_page_callback_t online_page_callback = generic_online_page; | 52 | static online_page_callback_t online_page_callback = generic_online_page; |
53 | static DEFINE_MUTEX(online_page_callback_lock); | 53 | static DEFINE_MUTEX(online_page_callback_lock); |
@@ -656,26 +656,39 @@ void __online_page_free(struct page *page) | |||
656 | } | 656 | } |
657 | EXPORT_SYMBOL_GPL(__online_page_free); | 657 | EXPORT_SYMBOL_GPL(__online_page_free); |
658 | 658 | ||
659 | static void generic_online_page(struct page *page) | 659 | static 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 | |||
669 | static 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 | ||
666 | static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, | 685 | static 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 | ||
1306 | static void __init __free_pages_boot_core(struct page *page, unsigned int order) | 1306 | void __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 | ||