kthread_stop never returns

Roman Kagan rkagan at mail.ru
Fri Jan 28 00:46:03 EST 2005


  Hi Duncan,

On Thu, Jan 27, 2005 at 06:03:49PM +0100, Duncan Sands wrote:
> On Thursday 27 January 2005 11:12, Duncan Sands wrote:
> > it seems that kthreads are supposed to run forever, and *only* exit when
> > kthread_should_stop is true.  This is not what we want.  I'll have to try
> > again...
> 
> It seems easy to fix.  Unfortunately work just got busy again, hopefully
> I can do it all tomorrow (promise!).

Sorta this?  (Just got up too early today :)

Compile- and briefly run-tested, including disconnects (both during the
heavy_init and after it has exited) and module unloading.

Cheers,
  Roman.


diff -u usbatm.h usbatm.h
--- usbatm.h	27 Jan 2005 13:08:35 -0000
+++ usbatm.h	28 Jan 2005 05:35:49 -0000
@@ -26,6 +26,7 @@
 
 #include <linux/config.h>
 #include <linux/list.h>
+#include <linux/completion.h>
 #include <linux/kref.h>
 #include <linux/atm.h>
 #include <linux/atmdev.h>
@@ -158,7 +159,7 @@
 	void *driver_data;
 
 	/* heavy thread part */
-	struct task_struct *kthread;
+	struct completion heavy_init_completion;
 
 	/* USB device part */
 	struct usb_device *usb_dev;
diff -u usbatm2.c usbatm2.c
--- usbatm2.c	27 Jan 2005 13:08:35 -0000
+++ usbatm2.c	28 Jan 2005 05:35:49 -0000
@@ -1020,30 +1020,30 @@
 	struct usbatm_data *instance = arg;
 	int ret;
 
+	daemonize("%s/%s", usbatm_driver_name, instance->driver->driver_name);
+
 	ret = instance->driver->heavy_init(instance, instance->usb_intf);
 
 	if (!ret)
 		ret = usbatm_atm_init(instance);
 
+	complete(&instance->heavy_init_completion);
+
 	return ret;
 }
 
-static long usbatm_heavy_init(struct usbatm_data *instance)
+static int usbatm_heavy_init(struct usbatm_data *instance)
 {
-	struct task_struct *kthread;
+	int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_FS | CLONE_FILES);
 
-	kthread = kthread_create(usbatm_do_heavy_init, instance, "%s/%s", usbatm_driver_name, instance->driver->driver_name);
+	if (ret >= 0)
+		return 0;
 
-	if (IS_ERR(kthread)) {
-		dbg("usbatm_heavy_init: kernel_thread failed (%ld)!", PTR_ERR(kthread));
-		return PTR_ERR(kthread);
-	}
+	dbg("usbatm_heavy_init: kernel_thread failed (%d)!", ret);
 
-	instance->kthread = kthread;
-	mb();
-	wake_up_process(kthread);
+	complete(&instance->heavy_init_completion);
 
-	return 0;
+	return ret;
 }
 
 static rwlock_t usbatm_driver_list_lock = RW_LOCK_UNLOCKED;
@@ -1084,6 +1084,8 @@
 
 	kref_init(&instance->refcount);	/* one for USB */
 
+	init_completion(&instance->heavy_init_completion);
+
 	init_MUTEX(&instance->serialize);
 
 	instance->driver = driver;
@@ -1200,8 +1202,11 @@
 
 	if (need_heavy && driver->heavy_init)
 		error = usbatm_heavy_init(instance);
-	else
+	else {
+		/* pretend that heavy_init was run */
+		complete(&instance->heavy_init_completion);
 		error = usbatm_atm_init(instance);
+	}
 
 	if (error)
 		goto fail;
@@ -1251,8 +1256,8 @@
 	if (instance->atm_dev && instance->driver->atm_stop)
 		instance->driver->atm_stop(instance, instance->atm_dev);
 
-	if (instance->kthread)
-		kthread_stop(instance->kthread);
+	/* hope heavy_init has already exited or will do so real soon */
+	wait_for_completion(&instance->heavy_init_completion);
 
 	if (instance->driver->unbind)
 		instance->driver->unbind(instance, intf);



More information about the Usbatm mailing list