diff options
Diffstat (limited to 'arch/s390/mm/cmm.c')
-rw-r--r-- | arch/s390/mm/cmm.c | 75 |
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; | |||
44 | static volatile long cmm_timed_pages_target; | 46 | static volatile long cmm_timed_pages_target; |
45 | static long cmm_timeout_pages; | 47 | static long cmm_timeout_pages; |
46 | static long cmm_timeout_seconds; | 48 | static long cmm_timeout_seconds; |
49 | static int cmm_suspended; | ||
47 | 50 | ||
48 | static struct cmm_page_array *cmm_page_list; | 51 | static struct cmm_page_array *cmm_page_list; |
49 | static struct cmm_page_array *cmm_timed_page_list; | 52 | static 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 | ||
361 | static struct ctl_table cmm_dir_table[] = { | 364 | static 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" |
375 | static void | 377 | static void |
376 | cmm_smsg_target(char *from, char *msg) | 378 | cmm_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 | ||
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); |