aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/cmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/cmm.c')
-rw-r--r--arch/s390/mm/cmm.c75
1 files changed, 57 insertions, 18 deletions
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index b201135cc18c..f87b34731e1d 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -12,12 +12,14 @@
12#include <linux/fs.h> 12#include <linux/fs.h>
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/gfp.h>
15#include <linux/sched.h> 16#include <linux/sched.h>
16#include <linux/sysctl.h> 17#include <linux/sysctl.h>
17#include <linux/ctype.h> 18#include <linux/ctype.h>
18#include <linux/swap.h> 19#include <linux/swap.h>
19#include <linux/kthread.h> 20#include <linux/kthread.h>
20#include <linux/oom.h> 21#include <linux/oom.h>
22#include <linux/suspend.h>
21 23
22#include <asm/pgalloc.h> 24#include <asm/pgalloc.h>
23#include <asm/uaccess.h> 25#include <asm/uaccess.h>
@@ -44,6 +46,7 @@ static volatile long cmm_pages_target;
44static volatile long cmm_timed_pages_target; 46static volatile long cmm_timed_pages_target;
45static long cmm_timeout_pages; 47static long cmm_timeout_pages;
46static long cmm_timeout_seconds; 48static long cmm_timeout_seconds;
49static int cmm_suspended;
47 50
48static struct cmm_page_array *cmm_page_list; 51static struct cmm_page_array *cmm_page_list;
49static struct cmm_page_array *cmm_timed_page_list; 52static struct cmm_page_array *cmm_timed_page_list;
@@ -147,9 +150,9 @@ cmm_thread(void *dummy)
147 150
148 while (1) { 151 while (1) {
149 rc = wait_event_interruptible(cmm_thread_wait, 152 rc = wait_event_interruptible(cmm_thread_wait,
150 (cmm_pages != cmm_pages_target || 153 (!cmm_suspended && (cmm_pages != cmm_pages_target ||
151 cmm_timed_pages != cmm_timed_pages_target || 154 cmm_timed_pages != cmm_timed_pages_target)) ||
152 kthread_should_stop())); 155 kthread_should_stop());
153 if (kthread_should_stop() || rc == -ERESTARTSYS) { 156 if (kthread_should_stop() || rc == -ERESTARTSYS) {
154 cmm_pages_target = cmm_pages; 157 cmm_pages_target = cmm_pages;
155 cmm_timed_pages_target = cmm_timed_pages; 158 cmm_timed_pages_target = cmm_timed_pages;
@@ -343,37 +346,36 @@ static struct ctl_table cmm_table[] = {
343 { 346 {
344 .procname = "cmm_pages", 347 .procname = "cmm_pages",
345 .mode = 0644, 348 .mode = 0644,
346 .proc_handler = &cmm_pages_handler, 349 .proc_handler = cmm_pages_handler,
347 }, 350 },
348 { 351 {
349 .procname = "cmm_timed_pages", 352 .procname = "cmm_timed_pages",
350 .mode = 0644, 353 .mode = 0644,
351 .proc_handler = &cmm_pages_handler, 354 .proc_handler = cmm_pages_handler,
352 }, 355 },
353 { 356 {
354 .procname = "cmm_timeout", 357 .procname = "cmm_timeout",
355 .mode = 0644, 358 .mode = 0644,
356 .proc_handler = &cmm_timeout_handler, 359 .proc_handler = cmm_timeout_handler,
357 }, 360 },
358 { .ctl_name = 0 } 361 { }
359}; 362};
360 363
361static struct ctl_table cmm_dir_table[] = { 364static struct ctl_table cmm_dir_table[] = {
362 { 365 {
363 .ctl_name = CTL_VM,
364 .procname = "vm", 366 .procname = "vm",
365 .maxlen = 0, 367 .maxlen = 0,
366 .mode = 0555, 368 .mode = 0555,
367 .child = cmm_table, 369 .child = cmm_table,
368 }, 370 },
369 { .ctl_name = 0 } 371 { }
370}; 372};
371#endif 373#endif
372 374
373#ifdef CONFIG_CMM_IUCV 375#ifdef CONFIG_CMM_IUCV
374#define SMSG_PREFIX "CMM" 376#define SMSG_PREFIX "CMM"
375static void 377static void
376cmm_smsg_target(char *from, char *msg) 378cmm_smsg_target(const char *from, char *msg)
377{ 379{
378 long nr, seconds; 380 long nr, seconds;
379 381
@@ -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);