[PATCH] s390: fix cmm kernel thread handling

Convert cmm's usage of kernel_thread to kthread_run. Also create the
cmmthread at module load time, so it is possible to check if creation of
the thread fails.

In addition the cmmthread now gets terminated when the module gets unloaded
instead of leaving a stale kernel thread. Also check the return values of
other registration functions at module load and handle their return values
appropriately.

Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Heiko Carstens and committed by Linus Torvalds e8216dee e8df8c33

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