Commit f2fe42ab authored by Dave Peterson's avatar Dave Peterson Committed by Linus Torvalds

[PATCH] EDAC: switch to kthread_ API

This patch was originally posted by Christoph Hellwig (see
http://lkml.org/lkml/2006/2/14/331):

"Christoph Hellwig" <hch@lst.de> wrote:
> Use the kthread_ API instead of opencoding lots of hairy code for kernel
> thread creation and teardown, including tasklist_lock abuse.
>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDavid S. Peterson <dsp@llnl.gov>
Cc: <dave_peterson@pobox.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent dac5bafa
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/kthread.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -64,6 +65,8 @@ static atomic_t pci_parity_count = ATOMIC_INIT(0); ...@@ -64,6 +65,8 @@ static atomic_t pci_parity_count = ATOMIC_INIT(0);
static DECLARE_MUTEX(mem_ctls_mutex); static DECLARE_MUTEX(mem_ctls_mutex);
static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
static struct task_struct *edac_thread;
/* Structure of the whitelist and blacklist arrays */ /* Structure of the whitelist and blacklist arrays */
struct edac_pci_device_list { struct edac_pci_device_list {
unsigned int vendor; /* Vendor ID */ unsigned int vendor; /* Vendor ID */
...@@ -2073,7 +2076,6 @@ static inline void check_mc_devices (void) ...@@ -2073,7 +2076,6 @@ static inline void check_mc_devices (void)
*/ */
static void do_edac_check(void) static void do_edac_check(void)
{ {
debugf3("MC: " __FILE__ ": %s()\n", __func__); debugf3("MC: " __FILE__ ": %s()\n", __func__);
check_mc_devices(); check_mc_devices();
...@@ -2081,62 +2083,16 @@ static void do_edac_check(void) ...@@ -2081,62 +2083,16 @@ static void do_edac_check(void)
do_pci_parity_check(); do_pci_parity_check();
} }
/*
* EDAC thread state information
*/
struct bs_thread_info
{
struct task_struct *task;
struct completion *event;
char *name;
void (*run)(void);
};
static struct bs_thread_info bs_thread;
/*
* edac_kernel_thread
* This the kernel thread that processes edac operations
* in a normal thread environment
*/
static int edac_kernel_thread(void *arg) static int edac_kernel_thread(void *arg)
{ {
struct bs_thread_info *thread = (struct bs_thread_info *) arg; while (!kthread_should_stop()) {
do_edac_check();
/* detach thread */
daemonize(thread->name);
current->exit_signal = SIGCHLD;
allow_signal(SIGKILL);
thread->task = current;
/* indicate to starting task we have started */
complete(thread->event);
/* loop forever, until we are told to stop */
while(thread->run != NULL) {
void (*run)(void);
/* call the function to check the memory controllers */
run = thread->run;
if (run)
run();
if (signal_pending(current))
flush_signals(current);
/* ensure we are interruptable */
set_current_state(TASK_INTERRUPTIBLE);
/* goto sleep for the interval */ /* goto sleep for the interval */
schedule_timeout((HZ * poll_msec) / 1000); schedule_timeout_interruptible((HZ * poll_msec) / 1000);
try_to_freeze(); try_to_freeze();
} }
/* notify waiter that we are exiting */
complete(thread->event);
return 0; return 0;
} }
...@@ -2146,9 +2102,6 @@ static int edac_kernel_thread(void *arg) ...@@ -2146,9 +2102,6 @@ static int edac_kernel_thread(void *arg)
*/ */
static int __init edac_mc_init(void) static int __init edac_mc_init(void)
{ {
int ret;
struct completion event;
printk(KERN_INFO "MC: " __FILE__ " version " EDAC_MC_VERSION "\n"); printk(KERN_INFO "MC: " __FILE__ " version " EDAC_MC_VERSION "\n");
/* /*
...@@ -2176,24 +2129,15 @@ static int __init edac_mc_init(void) ...@@ -2176,24 +2129,15 @@ static int __init edac_mc_init(void)
return -ENODEV; return -ENODEV;
} }
/* Create our kernel thread */
init_completion(&event);
bs_thread.event = &event;
bs_thread.name = "kedac";
bs_thread.run = do_edac_check;
/* create our kernel thread */ /* create our kernel thread */
ret = kernel_thread(edac_kernel_thread, &bs_thread, CLONE_KERNEL); edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
if (ret < 0) { if (IS_ERR(edac_thread)) {
/* remove the sysfs entries */ /* remove the sysfs entries */
edac_sysfs_memctrl_teardown(); edac_sysfs_memctrl_teardown();
edac_sysfs_pci_teardown(); edac_sysfs_pci_teardown();
return -ENOMEM; return PTR_ERR(edac_thread);
} }
/* wait for our kernel theard ack that it is up and running */
wait_for_completion(&event);
return 0; return 0;
} }
...@@ -2204,21 +2148,9 @@ static int __init edac_mc_init(void) ...@@ -2204,21 +2148,9 @@ static int __init edac_mc_init(void)
*/ */
static void __exit edac_mc_exit(void) static void __exit edac_mc_exit(void)
{ {
struct completion event;
debugf0("MC: " __FILE__ ": %s()\n", __func__); debugf0("MC: " __FILE__ ": %s()\n", __func__);
init_completion(&event); kthread_stop(edac_thread);
bs_thread.event = &event;
/* As soon as ->run is set to NULL, the task could disappear,
* so we need to hold tasklist_lock until we have sent the signal
*/
read_lock(&tasklist_lock);
bs_thread.run = NULL;
send_sig(SIGKILL, bs_thread.task, 1);
read_unlock(&tasklist_lock);
wait_for_completion(&event);
/* tear down the sysfs device */ /* tear down the sysfs device */
edac_sysfs_memctrl_teardown(); edac_sysfs_memctrl_teardown();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment