aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2009-12-07 06:52:06 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:37 -0500
commit52b169c864ea8622c4755172844fd24168c81195 (patch)
treeabd671fbc41dbc63b3c79bb8b7d317f081e6afa7 /arch
parent39475179d40996b4efa662e3825735a84d2526d1 (diff)
[S390] cmm: free pages on hibernate.
The pages allocated by the cmm memory balloon should be freed before the hibernation image is created. Otherwise the memory reserved by the balloon gets written to the swap device but there is no content in these pages that need to be preserved. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/mm/cmm.c61
1 files changed, 50 insertions, 11 deletions
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index b201135cc18c..5e5f3849660f 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -18,6 +18,7 @@
18#include <linux/swap.h> 18#include <linux/swap.h>
19#include <linux/kthread.h> 19#include <linux/kthread.h>
20#include <linux/oom.h> 20#include <linux/oom.h>
21#include <linux/suspend.h>
21 22
22#include <asm/pgalloc.h> 23#include <asm/pgalloc.h>
23#include <asm/uaccess.h> 24#include <asm/uaccess.h>
@@ -44,6 +45,7 @@ static volatile long cmm_pages_target;
44static volatile long cmm_timed_pages_target; 45static volatile long cmm_timed_pages_target;
45static long cmm_timeout_pages; 46static long cmm_timeout_pages;
46static long cmm_timeout_seconds; 47static long cmm_timeout_seconds;
48static int cmm_suspended;
47 49
48static struct cmm_page_array *cmm_page_list; 50static struct cmm_page_array *cmm_page_list;
49static struct cmm_page_array *cmm_timed_page_list; 51static struct cmm_page_array *cmm_timed_page_list;
@@ -147,9 +149,9 @@ cmm_thread(void *dummy)
147 149
148 while (1) { 150 while (1) {
149 rc = wait_event_interruptible(cmm_thread_wait, 151 rc = wait_event_interruptible(cmm_thread_wait,
150 (cmm_pages != cmm_pages_target || 152 (!cmm_suspended && (cmm_pages != cmm_pages_target ||
151 cmm_timed_pages != cmm_timed_pages_target || 153 cmm_timed_pages != cmm_timed_pages_target)) ||
152 kthread_should_stop())); 154 kthread_should_stop());
153 if (kthread_should_stop() || rc == -ERESTARTSYS) { 155 if (kthread_should_stop() || rc == -ERESTARTSYS) {
154 cmm_pages_target = cmm_pages; 156 cmm_pages_target = cmm_pages;
155 cmm_timed_pages_target = cmm_timed_pages; 157 cmm_timed_pages_target = cmm_timed_pages;
@@ -411,6 +413,38 @@ cmm_smsg_target(char *from, char *msg)
411 413
412static struct ctl_table_header *cmm_sysctl_header; 414static struct ctl_table_header *cmm_sysctl_header;
413 415
416static int cmm_suspend(void)
417{
418 cmm_suspended = 1;
419 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
420 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
421 return 0;
422}
423
424static int cmm_resume(void)
425{
426 cmm_suspended = 0;
427 cmm_kick_thread();
428 return 0;
429}
430
431static int cmm_power_event(struct notifier_block *this,
432 unsigned long event, void *ptr)
433{
434 switch (event) {
435 case PM_POST_HIBERNATION:
436 return cmm_resume();
437 case PM_HIBERNATION_PREPARE:
438 return cmm_suspend();
439 default:
440 return NOTIFY_DONE;
441 }
442}
443
444static struct notifier_block cmm_power_notifier = {
445 .notifier_call = cmm_power_event,
446};
447
414static int 448static int
415cmm_init (void) 449cmm_init (void)
416{ 450{
@@ -419,7 +453,7 @@ cmm_init (void)
419#ifdef CONFIG_CMM_PROC 453#ifdef CONFIG_CMM_PROC
420 cmm_sysctl_header = register_sysctl_table(cmm_dir_table); 454 cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
421 if (!cmm_sysctl_header) 455 if (!cmm_sysctl_header)
422 goto out; 456 goto out_sysctl;
423#endif 457#endif
424#ifdef CONFIG_CMM_IUCV 458#ifdef CONFIG_CMM_IUCV
425 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); 459 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -429,17 +463,21 @@ cmm_init (void)
429 rc = register_oom_notifier(&cmm_oom_nb); 463 rc = register_oom_notifier(&cmm_oom_nb);
430 if (rc < 0) 464 if (rc < 0)
431 goto out_oom_notify; 465 goto out_oom_notify;
466 rc = register_pm_notifier(&cmm_power_notifier);
467 if (rc)
468 goto out_pm;
432 init_waitqueue_head(&cmm_thread_wait); 469 init_waitqueue_head(&cmm_thread_wait);
433 init_timer(&cmm_timer); 470 init_timer(&cmm_timer);
434 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); 471 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
435 rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; 472 rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
436 if (!rc) 473 if (rc)
437 goto out; 474 goto out_kthread;
438 /* 475 return 0;
439 * kthread_create failed. undo all the stuff from above again.
440 */
441 unregister_oom_notifier(&cmm_oom_nb);
442 476
477out_kthread:
478 unregister_pm_notifier(&cmm_power_notifier);
479out_pm:
480 unregister_oom_notifier(&cmm_oom_nb);
443out_oom_notify: 481out_oom_notify:
444#ifdef CONFIG_CMM_IUCV 482#ifdef CONFIG_CMM_IUCV
445 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); 483 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
@@ -447,8 +485,8 @@ out_smsg:
447#endif 485#endif
448#ifdef CONFIG_CMM_PROC 486#ifdef CONFIG_CMM_PROC
449 unregister_sysctl_table(cmm_sysctl_header); 487 unregister_sysctl_table(cmm_sysctl_header);
488out_sysctl:
450#endif 489#endif
451out:
452 return rc; 490 return rc;
453} 491}
454 492
@@ -456,6 +494,7 @@ static void
456cmm_exit(void) 494cmm_exit(void)
457{ 495{
458 kthread_stop(cmm_thread_ptr); 496 kthread_stop(cmm_thread_ptr);
497 unregister_pm_notifier(&cmm_power_notifier);
459 unregister_oom_notifier(&cmm_oom_nb); 498 unregister_oom_notifier(&cmm_oom_nb);
460 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); 499 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
461 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); 500 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);