aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c12
-rw-r--r--drivers/base/memory.c44
-rw-r--r--include/linux/memory.h3
-rw-r--r--include/linux/memory_hotplug.h4
-rw-r--r--mm/memory_hotplug.c68
-rw-r--r--mm/sparse.c72
6 files changed, 113 insertions, 90 deletions
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 2372c609fa2b..9a432de363b8 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -72,6 +72,7 @@ unsigned long memory_block_size_bytes(void)
72 return get_memblock_size(); 72 return get_memblock_size();
73} 73}
74 74
75#ifdef CONFIG_MEMORY_HOTREMOVE
75static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size) 76static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
76{ 77{
77 unsigned long start, start_pfn; 78 unsigned long start, start_pfn;
@@ -153,6 +154,17 @@ static int pseries_remove_memory(struct device_node *np)
153 ret = pseries_remove_memblock(base, lmb_size); 154 ret = pseries_remove_memblock(base, lmb_size);
154 return ret; 155 return ret;
155} 156}
157#else
158static inline int pseries_remove_memblock(unsigned long base,
159 unsigned int memblock_size)
160{
161 return -EOPNOTSUPP;
162}
163static inline int pseries_remove_memory(struct device_node *np)
164{
165 return -EOPNOTSUPP;
166}
167#endif /* CONFIG_MEMORY_HOTREMOVE */
156 168
157static int pseries_add_memory(struct device_node *np) 169static int pseries_add_memory(struct device_node *np)
158{ 170{
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index a51007b79032..65d9799cbb61 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -93,16 +93,6 @@ int register_memory(struct memory_block *memory)
93 return error; 93 return error;
94} 94}
95 95
96static void
97unregister_memory(struct memory_block *memory)
98{
99 BUG_ON(memory->dev.bus != &memory_subsys);
100
101 /* drop the ref. we got in remove_memory_block() */
102 kobject_put(&memory->dev.kobj);
103 device_unregister(&memory->dev);
104}
105
106unsigned long __weak memory_block_size_bytes(void) 96unsigned long __weak memory_block_size_bytes(void)
107{ 97{
108 return MIN_MEMORY_BLOCK_SIZE; 98 return MIN_MEMORY_BLOCK_SIZE;
@@ -637,8 +627,28 @@ static int add_memory_section(int nid, struct mem_section *section,
637 return ret; 627 return ret;
638} 628}
639 629
640int remove_memory_block(unsigned long node_id, struct mem_section *section, 630/*
641 int phys_device) 631 * need an interface for the VM to add new memory regions,
632 * but without onlining it.
633 */
634int register_new_memory(int nid, struct mem_section *section)
635{
636 return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
637}
638
639#ifdef CONFIG_MEMORY_HOTREMOVE
640static void
641unregister_memory(struct memory_block *memory)
642{
643 BUG_ON(memory->dev.bus != &memory_subsys);
644
645 /* drop the ref. we got in remove_memory_block() */
646 kobject_put(&memory->dev.kobj);
647 device_unregister(&memory->dev);
648}
649
650static int remove_memory_block(unsigned long node_id,
651 struct mem_section *section, int phys_device)
642{ 652{
643 struct memory_block *mem; 653 struct memory_block *mem;
644 654
@@ -661,15 +671,6 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
661 return 0; 671 return 0;
662} 672}
663 673
664/*
665 * need an interface for the VM to add new memory regions,
666 * but without onlining it.
667 */
668int register_new_memory(int nid, struct mem_section *section)
669{
670 return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
671}
672
673int unregister_memory_section(struct mem_section *section) 674int unregister_memory_section(struct mem_section *section)
674{ 675{
675 if (!present_section(section)) 676 if (!present_section(section))
@@ -677,6 +678,7 @@ int unregister_memory_section(struct mem_section *section)
677 678
678 return remove_memory_block(0, section, 0); 679 return remove_memory_block(0, section, 0);
679} 680}
681#endif /* CONFIG_MEMORY_HOTREMOVE */
680 682
681/* 683/*
682 * offline one memory block. If the memory block has been offlined, do nothing. 684 * offline one memory block. If the memory block has been offlined, do nothing.
diff --git a/include/linux/memory.h b/include/linux/memory.h
index 0ff6598ee62f..73817af8b480 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -115,9 +115,10 @@ extern void unregister_memory_notifier(struct notifier_block *nb);
115extern int register_memory_isolate_notifier(struct notifier_block *nb); 115extern int register_memory_isolate_notifier(struct notifier_block *nb);
116extern void unregister_memory_isolate_notifier(struct notifier_block *nb); 116extern void unregister_memory_isolate_notifier(struct notifier_block *nb);
117extern int register_new_memory(int, struct mem_section *); 117extern int register_new_memory(int, struct mem_section *);
118#ifdef CONFIG_MEMORY_HOTREMOVE
118extern int unregister_memory_section(struct mem_section *); 119extern int unregister_memory_section(struct mem_section *);
120#endif
119extern int memory_dev_init(void); 121extern int memory_dev_init(void);
120extern int remove_memory_block(unsigned long, struct mem_section *, int);
121extern int memory_notify(unsigned long val, void *v); 122extern int memory_notify(unsigned long val, void *v);
122extern int memory_isolate_notify(unsigned long val, void *v); 123extern int memory_isolate_notify(unsigned long val, void *v);
123extern struct memory_block *find_memory_block_hinted(struct mem_section *, 124extern struct memory_block *find_memory_block_hinted(struct mem_section *,
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index b6a3be7d47bf..3e622c610925 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -97,13 +97,13 @@ extern void __online_page_free(struct page *page);
97#ifdef CONFIG_MEMORY_HOTREMOVE 97#ifdef CONFIG_MEMORY_HOTREMOVE
98extern bool is_pageblock_removable_nolock(struct page *page); 98extern bool is_pageblock_removable_nolock(struct page *page);
99extern int arch_remove_memory(u64 start, u64 size); 99extern int arch_remove_memory(u64 start, u64 size);
100extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
101 unsigned long nr_pages);
100#endif /* CONFIG_MEMORY_HOTREMOVE */ 102#endif /* CONFIG_MEMORY_HOTREMOVE */
101 103
102/* reasonably generic interface to expand the physical pages in a zone */ 104/* reasonably generic interface to expand the physical pages in a zone */
103extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn, 105extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn,
104 unsigned long nr_pages); 106 unsigned long nr_pages);
105extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
106 unsigned long nr_pages);
107 107
108#ifdef CONFIG_NUMA 108#ifdef CONFIG_NUMA
109extern int memory_add_physaddr_to_nid(u64 start); 109extern int memory_add_physaddr_to_nid(u64 start);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index c916582591eb..60f6daad1076 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -436,6 +436,40 @@ static int __meminit __add_section(int nid, struct zone *zone,
436 return register_new_memory(nid, __pfn_to_section(phys_start_pfn)); 436 return register_new_memory(nid, __pfn_to_section(phys_start_pfn));
437} 437}
438 438
439/*
440 * Reasonably generic function for adding memory. It is
441 * expected that archs that support memory hotplug will
442 * call this function after deciding the zone to which to
443 * add the new pages.
444 */
445int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
446 unsigned long nr_pages)
447{
448 unsigned long i;
449 int err = 0;
450 int start_sec, end_sec;
451 /* during initialize mem_map, align hot-added range to section */
452 start_sec = pfn_to_section_nr(phys_start_pfn);
453 end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
454
455 for (i = start_sec; i <= end_sec; i++) {
456 err = __add_section(nid, zone, i << PFN_SECTION_SHIFT);
457
458 /*
459 * EEXIST is finally dealt with by ioresource collision
460 * check. see add_memory() => register_memory_resource()
461 * Warning will be printed if there is collision.
462 */
463 if (err && (err != -EEXIST))
464 break;
465 err = 0;
466 }
467
468 return err;
469}
470EXPORT_SYMBOL_GPL(__add_pages);
471
472#ifdef CONFIG_MEMORY_HOTREMOVE
439/* find the smallest valid pfn in the range [start_pfn, end_pfn) */ 473/* find the smallest valid pfn in the range [start_pfn, end_pfn) */
440static int find_smallest_section_pfn(int nid, struct zone *zone, 474static int find_smallest_section_pfn(int nid, struct zone *zone,
441 unsigned long start_pfn, 475 unsigned long start_pfn,
@@ -658,39 +692,6 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)
658 return 0; 692 return 0;
659} 693}
660 694
661/*
662 * Reasonably generic function for adding memory. It is
663 * expected that archs that support memory hotplug will
664 * call this function after deciding the zone to which to
665 * add the new pages.
666 */
667int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
668 unsigned long nr_pages)
669{
670 unsigned long i;
671 int err = 0;
672 int start_sec, end_sec;
673 /* during initialize mem_map, align hot-added range to section */
674 start_sec = pfn_to_section_nr(phys_start_pfn);
675 end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
676
677 for (i = start_sec; i <= end_sec; i++) {
678 err = __add_section(nid, zone, i << PFN_SECTION_SHIFT);
679
680 /*
681 * EEXIST is finally dealt with by ioresource collision
682 * check. see add_memory() => register_memory_resource()
683 * Warning will be printed if there is collision.
684 */
685 if (err && (err != -EEXIST))
686 break;
687 err = 0;
688 }
689
690 return err;
691}
692EXPORT_SYMBOL_GPL(__add_pages);
693
694/** 695/**
695 * __remove_pages() - remove sections of pages from a zone 696 * __remove_pages() - remove sections of pages from a zone
696 * @zone: zone from which pages need to be removed 697 * @zone: zone from which pages need to be removed
@@ -733,6 +734,7 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
733 return ret; 734 return ret;
734} 735}
735EXPORT_SYMBOL_GPL(__remove_pages); 736EXPORT_SYMBOL_GPL(__remove_pages);
737#endif /* CONFIG_MEMORY_HOTREMOVE */
736 738
737int set_online_page_callback(online_page_callback_t callback) 739int set_online_page_callback(online_page_callback_t callback)
738{ 740{
diff --git a/mm/sparse.c b/mm/sparse.c
index a37be5f9050d..1c91f0d3f6ab 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -620,6 +620,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
620 620
621 vmemmap_free(start, end); 621 vmemmap_free(start, end);
622} 622}
623#ifdef CONFIG_MEMORY_HOTREMOVE
623static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) 624static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
624{ 625{
625 unsigned long start = (unsigned long)memmap; 626 unsigned long start = (unsigned long)memmap;
@@ -627,6 +628,7 @@ static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
627 628
628 vmemmap_free(start, end); 629 vmemmap_free(start, end);
629} 630}
631#endif /* CONFIG_MEMORY_HOTREMOVE */
630#else 632#else
631static struct page *__kmalloc_section_memmap(unsigned long nr_pages) 633static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
632{ 634{
@@ -664,6 +666,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
664 get_order(sizeof(struct page) * nr_pages)); 666 get_order(sizeof(struct page) * nr_pages));
665} 667}
666 668
669#ifdef CONFIG_MEMORY_HOTREMOVE
667static void free_map_bootmem(struct page *memmap, unsigned long nr_pages) 670static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
668{ 671{
669 unsigned long maps_section_nr, removing_section_nr, i; 672 unsigned long maps_section_nr, removing_section_nr, i;
@@ -690,40 +693,9 @@ static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
690 put_page_bootmem(page); 693 put_page_bootmem(page);
691 } 694 }
692} 695}
696#endif /* CONFIG_MEMORY_HOTREMOVE */
693#endif /* CONFIG_SPARSEMEM_VMEMMAP */ 697#endif /* CONFIG_SPARSEMEM_VMEMMAP */
694 698
695static void free_section_usemap(struct page *memmap, unsigned long *usemap)
696{
697 struct page *usemap_page;
698 unsigned long nr_pages;
699
700 if (!usemap)
701 return;
702
703 usemap_page = virt_to_page(usemap);
704 /*
705 * Check to see if allocation came from hot-plug-add
706 */
707 if (PageSlab(usemap_page) || PageCompound(usemap_page)) {
708 kfree(usemap);
709 if (memmap)
710 __kfree_section_memmap(memmap, PAGES_PER_SECTION);
711 return;
712 }
713
714 /*
715 * The usemap came from bootmem. This is packed with other usemaps
716 * on the section which has pgdat at boot time. Just keep it as is now.
717 */
718
719 if (memmap) {
720 nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
721 >> PAGE_SHIFT;
722
723 free_map_bootmem(memmap, nr_pages);
724 }
725}
726
727/* 699/*
728 * returns the number of sections whose mem_maps were properly 700 * returns the number of sections whose mem_maps were properly
729 * set. If this is <=0, then that means that the passed-in 701 * set. If this is <=0, then that means that the passed-in
@@ -800,6 +772,39 @@ static inline void clear_hwpoisoned_pages(struct page *memmap, int nr_pages)
800} 772}
801#endif 773#endif
802 774
775#ifdef CONFIG_MEMORY_HOTREMOVE
776static void free_section_usemap(struct page *memmap, unsigned long *usemap)
777{
778 struct page *usemap_page;
779 unsigned long nr_pages;
780
781 if (!usemap)
782 return;
783
784 usemap_page = virt_to_page(usemap);
785 /*
786 * Check to see if allocation came from hot-plug-add
787 */
788 if (PageSlab(usemap_page) || PageCompound(usemap_page)) {
789 kfree(usemap);
790 if (memmap)
791 __kfree_section_memmap(memmap, PAGES_PER_SECTION);
792 return;
793 }
794
795 /*
796 * The usemap came from bootmem. This is packed with other usemaps
797 * on the section which has pgdat at boot time. Just keep it as is now.
798 */
799
800 if (memmap) {
801 nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
802 >> PAGE_SHIFT;
803
804 free_map_bootmem(memmap, nr_pages);
805 }
806}
807
803void sparse_remove_one_section(struct zone *zone, struct mem_section *ms) 808void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
804{ 809{
805 struct page *memmap = NULL; 810 struct page *memmap = NULL;
@@ -819,4 +824,5 @@ void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
819 clear_hwpoisoned_pages(memmap, PAGES_PER_SECTION); 824 clear_hwpoisoned_pages(memmap, PAGES_PER_SECTION);
820 free_section_usemap(memmap, usemap); 825 free_section_usemap(memmap, usemap);
821} 826}
822#endif 827#endif /* CONFIG_MEMORY_HOTREMOVE */
828#endif /* CONFIG_MEMORY_HOTPLUG */