diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-12-07 06:52:06 -0500 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2009-12-07 06:51:37 -0500 |
commit | 52b169c864ea8622c4755172844fd24168c81195 (patch) | |
tree | abd671fbc41dbc63b3c79bb8b7d317f081e6afa7 /arch | |
parent | 39475179d40996b4efa662e3825735a84d2526d1 (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.c | 61 |
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; | |||
44 | static volatile long cmm_timed_pages_target; | 45 | static volatile long cmm_timed_pages_target; |
45 | static long cmm_timeout_pages; | 46 | static long cmm_timeout_pages; |
46 | static long cmm_timeout_seconds; | 47 | static long cmm_timeout_seconds; |
48 | static int cmm_suspended; | ||
47 | 49 | ||
48 | static struct cmm_page_array *cmm_page_list; | 50 | static struct cmm_page_array *cmm_page_list; |
49 | static struct cmm_page_array *cmm_timed_page_list; | 51 | static 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 | ||
412 | static struct ctl_table_header *cmm_sysctl_header; | 414 | static struct ctl_table_header *cmm_sysctl_header; |
413 | 415 | ||
416 | static 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 | |||
424 | static int cmm_resume(void) | ||
425 | { | ||
426 | cmm_suspended = 0; | ||
427 | cmm_kick_thread(); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static 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 | |||
444 | static struct notifier_block cmm_power_notifier = { | ||
445 | .notifier_call = cmm_power_event, | ||
446 | }; | ||
447 | |||
414 | static int | 448 | static int |
415 | cmm_init (void) | 449 | cmm_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 | ||
477 | out_kthread: | ||
478 | unregister_pm_notifier(&cmm_power_notifier); | ||
479 | out_pm: | ||
480 | unregister_oom_notifier(&cmm_oom_nb); | ||
443 | out_oom_notify: | 481 | out_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); |
488 | out_sysctl: | ||
450 | #endif | 489 | #endif |
451 | out: | ||
452 | return rc; | 490 | return rc; |
453 | } | 491 | } |
454 | 492 | ||
@@ -456,6 +494,7 @@ static void | |||
456 | cmm_exit(void) | 494 | cmm_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); |