diff options
Diffstat (limited to 'arch/s390/mm/cmm.c')
-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 ff58779bf7e9..76a3637b88e0 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; |
@@ -410,6 +412,38 @@ cmm_smsg_target(char *from, char *msg) | |||
410 | 412 | ||
411 | static struct ctl_table_header *cmm_sysctl_header; | 413 | static struct ctl_table_header *cmm_sysctl_header; |
412 | 414 | ||
415 | static int cmm_suspend(void) | ||
416 | { | ||
417 | cmm_suspended = 1; | ||
418 | cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); | ||
419 | cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int cmm_resume(void) | ||
424 | { | ||
425 | cmm_suspended = 0; | ||
426 | cmm_kick_thread(); | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int cmm_power_event(struct notifier_block *this, | ||
431 | unsigned long event, void *ptr) | ||
432 | { | ||
433 | switch (event) { | ||
434 | case PM_POST_HIBERNATION: | ||
435 | return cmm_resume(); | ||
436 | case PM_HIBERNATION_PREPARE: | ||
437 | return cmm_suspend(); | ||
438 | default: | ||
439 | return NOTIFY_DONE; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | static struct notifier_block cmm_power_notifier = { | ||
444 | .notifier_call = cmm_power_event, | ||
445 | }; | ||
446 | |||
413 | static int | 447 | static int |
414 | cmm_init (void) | 448 | cmm_init (void) |
415 | { | 449 | { |
@@ -418,7 +452,7 @@ cmm_init (void) | |||
418 | #ifdef CONFIG_CMM_PROC | 452 | #ifdef CONFIG_CMM_PROC |
419 | cmm_sysctl_header = register_sysctl_table(cmm_dir_table); | 453 | cmm_sysctl_header = register_sysctl_table(cmm_dir_table); |
420 | if (!cmm_sysctl_header) | 454 | if (!cmm_sysctl_header) |
421 | goto out; | 455 | goto out_sysctl; |
422 | #endif | 456 | #endif |
423 | #ifdef CONFIG_CMM_IUCV | 457 | #ifdef CONFIG_CMM_IUCV |
424 | rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); | 458 | rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); |
@@ -428,17 +462,21 @@ cmm_init (void) | |||
428 | rc = register_oom_notifier(&cmm_oom_nb); | 462 | rc = register_oom_notifier(&cmm_oom_nb); |
429 | if (rc < 0) | 463 | if (rc < 0) |
430 | goto out_oom_notify; | 464 | goto out_oom_notify; |
465 | rc = register_pm_notifier(&cmm_power_notifier); | ||
466 | if (rc) | ||
467 | goto out_pm; | ||
431 | init_waitqueue_head(&cmm_thread_wait); | 468 | init_waitqueue_head(&cmm_thread_wait); |
432 | init_timer(&cmm_timer); | 469 | init_timer(&cmm_timer); |
433 | cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); | 470 | cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); |
434 | rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; | 471 | rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; |
435 | if (!rc) | 472 | if (rc) |
436 | goto out; | 473 | goto out_kthread; |
437 | /* | 474 | return 0; |
438 | * kthread_create failed. undo all the stuff from above again. | ||
439 | */ | ||
440 | unregister_oom_notifier(&cmm_oom_nb); | ||
441 | 475 | ||
476 | out_kthread: | ||
477 | unregister_pm_notifier(&cmm_power_notifier); | ||
478 | out_pm: | ||
479 | unregister_oom_notifier(&cmm_oom_nb); | ||
442 | out_oom_notify: | 480 | out_oom_notify: |
443 | #ifdef CONFIG_CMM_IUCV | 481 | #ifdef CONFIG_CMM_IUCV |
444 | smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); | 482 | smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); |
@@ -446,8 +484,8 @@ out_smsg: | |||
446 | #endif | 484 | #endif |
447 | #ifdef CONFIG_CMM_PROC | 485 | #ifdef CONFIG_CMM_PROC |
448 | unregister_sysctl_table(cmm_sysctl_header); | 486 | unregister_sysctl_table(cmm_sysctl_header); |
487 | out_sysctl: | ||
449 | #endif | 488 | #endif |
450 | out: | ||
451 | return rc; | 489 | return rc; |
452 | } | 490 | } |
453 | 491 | ||
@@ -455,6 +493,7 @@ static void | |||
455 | cmm_exit(void) | 493 | cmm_exit(void) |
456 | { | 494 | { |
457 | kthread_stop(cmm_thread_ptr); | 495 | kthread_stop(cmm_thread_ptr); |
496 | unregister_pm_notifier(&cmm_power_notifier); | ||
458 | unregister_oom_notifier(&cmm_oom_nb); | 497 | unregister_oom_notifier(&cmm_oom_nb); |
459 | cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); | 498 | cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); |
460 | cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); | 499 | cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); |