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); |