diff options
| -rw-r--r-- | arch/s390/mm/cmm.c | 54 |
1 files changed, 35 insertions, 19 deletions
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index f2e00df99bae..607f50ead1fd 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/sysctl.h> | 16 | #include <linux/sysctl.h> |
| 17 | #include <linux/ctype.h> | 17 | #include <linux/ctype.h> |
| 18 | #include <linux/swap.h> | 18 | #include <linux/swap.h> |
| 19 | #include <linux/kthread.h> | ||
| 19 | 20 | ||
| 20 | #include <asm/pgalloc.h> | 21 | #include <asm/pgalloc.h> |
| 21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| @@ -46,8 +47,7 @@ static struct cmm_page_array *cmm_page_list; | |||
| 46 | static struct cmm_page_array *cmm_timed_page_list; | 47 | static struct cmm_page_array *cmm_timed_page_list; |
| 47 | static DEFINE_SPINLOCK(cmm_lock); | 48 | static DEFINE_SPINLOCK(cmm_lock); |
| 48 | 49 | ||
| 49 | static unsigned long cmm_thread_active; | 50 | static struct task_struct *cmm_thread_ptr; |
| 50 | static struct work_struct cmm_thread_starter; | ||
| 51 | static wait_queue_head_t cmm_thread_wait; | 51 | static wait_queue_head_t cmm_thread_wait; |
| 52 | static struct timer_list cmm_timer; | 52 | static struct timer_list cmm_timer; |
| 53 | 53 | ||
| @@ -143,14 +143,12 @@ cmm_thread(void *dummy) | |||
| 143 | { | 143 | { |
| 144 | int rc; | 144 | int rc; |
| 145 | 145 | ||
| 146 | daemonize("cmmthread"); | ||
| 147 | while (1) { | 146 | while (1) { |
| 148 | rc = wait_event_interruptible(cmm_thread_wait, | 147 | rc = wait_event_interruptible(cmm_thread_wait, |
| 149 | (cmm_pages != cmm_pages_target || | 148 | (cmm_pages != cmm_pages_target || |
| 150 | cmm_timed_pages != cmm_timed_pages_target)); | 149 | cmm_timed_pages != cmm_timed_pages_target || |
| 151 | if (rc == -ERESTARTSYS) { | 150 | kthread_should_stop())); |
| 152 | /* Got kill signal. End thread. */ | 151 | if (kthread_should_stop() || rc == -ERESTARTSYS) { |
| 153 | clear_bit(0, &cmm_thread_active); | ||
| 154 | cmm_pages_target = cmm_pages; | 152 | cmm_pages_target = cmm_pages; |
| 155 | cmm_timed_pages_target = cmm_timed_pages; | 153 | cmm_timed_pages_target = cmm_timed_pages; |
| 156 | break; | 154 | break; |
| @@ -176,16 +174,8 @@ cmm_thread(void *dummy) | |||
| 176 | } | 174 | } |
| 177 | 175 | ||
| 178 | static void | 176 | static void |
| 179 | cmm_start_thread(void) | ||
| 180 | { | ||
| 181 | kernel_thread(cmm_thread, NULL, 0); | ||
| 182 | } | ||
| 183 | |||
| 184 | static void | ||
| 185 | cmm_kick_thread(void) | 177 | cmm_kick_thread(void) |
| 186 | { | 178 | { |
| 187 | if (!test_and_set_bit(0, &cmm_thread_active)) | ||
| 188 | schedule_work(&cmm_thread_starter); | ||
| 189 | wake_up(&cmm_thread_wait); | 179 | wake_up(&cmm_thread_wait); |
| 190 | } | 180 | } |
| 191 | 181 | ||
| @@ -429,22 +419,48 @@ struct ctl_table_header *cmm_sysctl_header; | |||
| 429 | static int | 419 | static int |
| 430 | cmm_init (void) | 420 | cmm_init (void) |
| 431 | { | 421 | { |
| 422 | int rc = -ENOMEM; | ||
| 423 | |||
| 432 | #ifdef CONFIG_CMM_PROC | 424 | #ifdef CONFIG_CMM_PROC |
| 433 | cmm_sysctl_header = register_sysctl_table(cmm_dir_table, 1); | 425 | cmm_sysctl_header = register_sysctl_table(cmm_dir_table, 1); |
| 426 | if (!cmm_sysctl_header) | ||
| 427 | goto out; | ||
| 434 | #endif | 428 | #endif |
| 435 | #ifdef CONFIG_CMM_IUCV | 429 | #ifdef CONFIG_CMM_IUCV |
| 436 | smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); | 430 | rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); |
| 431 | if (rc < 0) | ||
| 432 | goto out_smsg; | ||
| 437 | #endif | 433 | #endif |
| 438 | register_oom_notifier(&cmm_oom_nb); | 434 | rc = register_oom_notifier(&cmm_oom_nb); |
| 439 | INIT_WORK(&cmm_thread_starter, (void *) cmm_start_thread, NULL); | 435 | if (rc < 0) |
| 436 | goto out_oom_notify; | ||
| 440 | init_waitqueue_head(&cmm_thread_wait); | 437 | init_waitqueue_head(&cmm_thread_wait); |
| 441 | init_timer(&cmm_timer); | 438 | init_timer(&cmm_timer); |
| 442 | return 0; | 439 | cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); |
| 440 | rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; | ||
| 441 | if (!rc) | ||
| 442 | goto out; | ||
| 443 | /* | ||
| 444 | * kthread_create failed. undo all the stuff from above again. | ||
| 445 | */ | ||
| 446 | unregister_oom_notifier(&cmm_oom_nb); | ||
| 447 | |||
| 448 | out_oom_notify: | ||
| 449 | #ifdef CONFIG_CMM_IUCV | ||
| 450 | smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); | ||
| 451 | out_smsg: | ||
| 452 | #endif | ||
| 453 | #ifdef CONFIG_CMM_PROC | ||
| 454 | unregister_sysctl_table(cmm_sysctl_header); | ||
| 455 | #endif | ||
| 456 | out: | ||
| 457 | return rc; | ||
| 443 | } | 458 | } |
| 444 | 459 | ||
| 445 | static void | 460 | static void |
| 446 | cmm_exit(void) | 461 | cmm_exit(void) |
| 447 | { | 462 | { |
| 463 | kthread_stop(cmm_thread_ptr); | ||
| 448 | unregister_oom_notifier(&cmm_oom_nb); | 464 | unregister_oom_notifier(&cmm_oom_nb); |
| 449 | cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); | 465 | cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); |
| 450 | cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); | 466 | cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); |
