aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <andi@firstfloor.org>2009-11-17 17:06:22 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-11-17 20:40:33 -0500
commit6ad696d2cf535772dff659298ec7e7260e344595 (patch)
tree2f4d4d088a7bc8203473dcb96a1d1f0591f3de94
parent9398180097e359646d46083c3e079a54e20bee82 (diff)
mm: allow memory hotplug and hibernation in the same kernel
Allow memory hotplug and hibernation in the same kernel Memory hotplug and hibernation were exclusive in Kconfig. This is obviously a problem for distribution kernels who want to support both in the same image. After some discussions with Rafael and others the only problem is with parallel memory hotadd or removal while a hibernation operation is in process. It was also working for s390 before. This patch removes the Kconfig level exclusion, and simply makes the memory add / remove functions grab the pm_mutex to exclude against hibernation. Fixes a regression - old kernels didn't exclude memory hotadd and hibernation. Signed-off-by: Andi Kleen <ak@linux.intel.com> Cc: Gerald Schaefer <gerald.schaefer@de.ibm.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Yasunori Goto <y-goto@jp.fujitsu.com> Acked-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/suspend.h21
-rw-r--r--mm/Kconfig5
-rw-r--r--mm/memory_hotplug.c21
3 files changed, 37 insertions, 10 deletions
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index cd15df6c63cd..5e781d824e6d 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -301,6 +301,8 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
301#define pm_notifier(fn, pri) do { (void)(fn); } while (0) 301#define pm_notifier(fn, pri) do { (void)(fn); } while (0)
302#endif /* !CONFIG_PM_SLEEP */ 302#endif /* !CONFIG_PM_SLEEP */
303 303
304extern struct mutex pm_mutex;
305
304#ifndef CONFIG_HIBERNATION 306#ifndef CONFIG_HIBERNATION
305static inline void register_nosave_region(unsigned long b, unsigned long e) 307static inline void register_nosave_region(unsigned long b, unsigned long e)
306{ 308{
@@ -308,8 +310,23 @@ static inline void register_nosave_region(unsigned long b, unsigned long e)
308static inline void register_nosave_region_late(unsigned long b, unsigned long e) 310static inline void register_nosave_region_late(unsigned long b, unsigned long e)
309{ 311{
310} 312}
311#endif
312 313
313extern struct mutex pm_mutex; 314static inline void lock_system_sleep(void) {}
315static inline void unlock_system_sleep(void) {}
316
317#else
318
319/* Let some subsystems like memory hotadd exclude hibernation */
320
321static inline void lock_system_sleep(void)
322{
323 mutex_lock(&pm_mutex);
324}
325
326static inline void unlock_system_sleep(void)
327{
328 mutex_unlock(&pm_mutex);
329}
330#endif
314 331
315#endif /* _LINUX_SUSPEND_H */ 332#endif /* _LINUX_SUSPEND_H */
diff --git a/mm/Kconfig b/mm/Kconfig
index fd3386242cf0..44cf6f0a3a6d 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -128,12 +128,9 @@ config SPARSEMEM_VMEMMAP
128config MEMORY_HOTPLUG 128config MEMORY_HOTPLUG
129 bool "Allow for memory hot-add" 129 bool "Allow for memory hot-add"
130 depends on SPARSEMEM || X86_64_ACPI_NUMA 130 depends on SPARSEMEM || X86_64_ACPI_NUMA
131 depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG 131 depends on HOTPLUG && ARCH_ENABLE_MEMORY_HOTPLUG
132 depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390) 132 depends on (IA64 || X86 || PPC_BOOK3S_64 || SUPERH || S390)
133 133
134comment "Memory hotplug is currently incompatible with Software Suspend"
135 depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390
136
137config MEMORY_HOTPLUG_SPARSE 134config MEMORY_HOTPLUG_SPARSE
138 def_bool y 135 def_bool y
139 depends on SPARSEMEM && MEMORY_HOTPLUG 136 depends on SPARSEMEM && MEMORY_HOTPLUG
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 380aef45c2cf..2047465cd27c 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -26,6 +26,7 @@
26#include <linux/migrate.h> 26#include <linux/migrate.h>
27#include <linux/page-isolation.h> 27#include <linux/page-isolation.h>
28#include <linux/pfn.h> 28#include <linux/pfn.h>
29#include <linux/suspend.h>
29 30
30#include <asm/tlbflush.h> 31#include <asm/tlbflush.h>
31 32
@@ -485,14 +486,18 @@ int __ref add_memory(int nid, u64 start, u64 size)
485 struct resource *res; 486 struct resource *res;
486 int ret; 487 int ret;
487 488
489 lock_system_sleep();
490
488 res = register_memory_resource(start, size); 491 res = register_memory_resource(start, size);
492 ret = -EEXIST;
489 if (!res) 493 if (!res)
490 return -EEXIST; 494 goto out;
491 495
492 if (!node_online(nid)) { 496 if (!node_online(nid)) {
493 pgdat = hotadd_new_pgdat(nid, start); 497 pgdat = hotadd_new_pgdat(nid, start);
498 ret = -ENOMEM;
494 if (!pgdat) 499 if (!pgdat)
495 return -ENOMEM; 500 goto out;
496 new_pgdat = 1; 501 new_pgdat = 1;
497 } 502 }
498 503
@@ -515,7 +520,8 @@ int __ref add_memory(int nid, u64 start, u64 size)
515 BUG_ON(ret); 520 BUG_ON(ret);
516 } 521 }
517 522
518 return ret; 523 goto out;
524
519error: 525error:
520 /* rollback pgdat allocation and others */ 526 /* rollback pgdat allocation and others */
521 if (new_pgdat) 527 if (new_pgdat)
@@ -523,6 +529,8 @@ error:
523 if (res) 529 if (res)
524 release_memory_resource(res); 530 release_memory_resource(res);
525 531
532out:
533 unlock_system_sleep();
526 return ret; 534 return ret;
527} 535}
528EXPORT_SYMBOL_GPL(add_memory); 536EXPORT_SYMBOL_GPL(add_memory);
@@ -759,6 +767,8 @@ int offline_pages(unsigned long start_pfn,
759 if (!test_pages_in_a_zone(start_pfn, end_pfn)) 767 if (!test_pages_in_a_zone(start_pfn, end_pfn))
760 return -EINVAL; 768 return -EINVAL;
761 769
770 lock_system_sleep();
771
762 zone = page_zone(pfn_to_page(start_pfn)); 772 zone = page_zone(pfn_to_page(start_pfn));
763 node = zone_to_nid(zone); 773 node = zone_to_nid(zone);
764 nr_pages = end_pfn - start_pfn; 774 nr_pages = end_pfn - start_pfn;
@@ -766,7 +776,7 @@ int offline_pages(unsigned long start_pfn,
766 /* set above range as isolated */ 776 /* set above range as isolated */
767 ret = start_isolate_page_range(start_pfn, end_pfn); 777 ret = start_isolate_page_range(start_pfn, end_pfn);
768 if (ret) 778 if (ret)
769 return ret; 779 goto out;
770 780
771 arg.start_pfn = start_pfn; 781 arg.start_pfn = start_pfn;
772 arg.nr_pages = nr_pages; 782 arg.nr_pages = nr_pages;
@@ -844,6 +854,7 @@ repeat:
844 writeback_set_ratelimit(); 854 writeback_set_ratelimit();
845 855
846 memory_notify(MEM_OFFLINE, &arg); 856 memory_notify(MEM_OFFLINE, &arg);
857 unlock_system_sleep();
847 return 0; 858 return 0;
848 859
849failed_removal: 860failed_removal:
@@ -853,6 +864,8 @@ failed_removal:
853 /* pushback to free area */ 864 /* pushback to free area */
854 undo_isolate_page_range(start_pfn, end_pfn); 865 undo_isolate_page_range(start_pfn, end_pfn);
855 866
867out:
868 unlock_system_sleep();
856 return ret; 869 return ret;
857} 870}
858 871