Skip to contentSkip to conversation

fix EH thread teardown

PATCH In review Christoph Hellwig 2 participants 3 messages Sep 7, 2005 – Sep 8, 2005 SCSI

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 fix EH thread teardown

As Rolf Eike Beer noted we might not actually get to the kthread_should_stop() because we are waiting in the semaphore forever. I didn't get a rmmod hang because of this, but my instrumentation showed the thread defitiyly didn't exit.

So make sure to wake the EH thread before the kthread_stop, and to plug the reaming race check kthead_should_stop() a second time just before calling down_interruptible().

drivers/scsi/hosts.c +3 -1
Index: scsi-misc-2.6/drivers/scsi/hosts.c
===================================================================
@@ -226,8 +226,10 @@
 	struct Scsi_Host *shost = dev_to_shost(dev);
 	struct device *parent = dev->parent;
 
-	if (shost->ehandler)
+	if (shost->ehandler) {
+		up(shost->eh_wait);
 		kthread_stop(shost->ehandler);
+	}
 	if (shost->work_q)
 		destroy_workqueue(shost->work_q);
 
drivers/scsi/scsi_error.c +1 -1
Index: scsi-misc-2.6/drivers/scsi/scsi_error.c
===================================================================
@@ -1591,7 +1591,7 @@
 	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of"
 					  " scsi_eh_%d\n",shost->host_no));
 
-	while (1) {
+	while (!kthread_should_stop()) {
 		/*
 		 * If we get a signal, it means we are supposed to go
 		 * away and die.  This typically happens if the user is
#1 lore raw
Quoted 23 lines · Christoph Hellwig

As Rolf Eike Beer noted we might not actually get to the kthread_should_stop() because we are waiting in the semaphore forever. I didn't get a rmmod hang because of this, but my instrumentation showed the thread defitiyly didn't exit.

So make sure to wake the EH thread before the kthread_stop, and to plug the reaming race check kthead_should_stop() a second time just before calling down_interruptible().

Index: scsi-misc-2.6/drivers/scsi/hosts.c
===================================================================
--- scsi-misc-2.6.orig/drivers/scsi/hosts.c 2005-09-07 14:21:44.000000000
+0200 +++ scsi-misc-2.6/drivers/scsi/hosts.c 2005-09-07 14:22:33.000000000
+0200 @@ -226,8 +226,10 @@

	struct Scsi_Host *shost = dev_to_shost(dev);
	struct device *parent = dev->parent;
drivers/scsi/hosts.c +2 -1
-	if (shost->ehandler)
+	if (shost->ehandler) {
+		up(shost->eh_wait);
		kthread_stop(shost->ehandler);
drivers/scsi/hosts.c +1 -0
+	}
Quoted 2 lines
	if (shost->work_q)
		destroy_workqueue(shost->work_q);

Wouldn't this hang the same way if rescheduling happens between the up() and the kthread_stop()?

Eike

#2 lore raw
In reply to Christoph Hellwig
Quoted 8 lines · Christoph Hellwig

As Rolf Eike Beer noted we might not actually get to the kthread_should_stop() because we are waiting in the semaphore forever. I didn't get a rmmod hang because of this, but my instrumentation showed the thread defitiyly didn't exit.

So make sure to wake the EH thread before the kthread_stop, and to plug the reaming race check kthead_should_stop() a second time just before calling down_interruptible().

Ok, we looked a bit closer on all this. http://lwn.net/Articles/65178/ tells that ktread_stop() will not send a signal, so the down_interruptible() will never return on kthread_stop(). But calling up() directly before kthread_stop() adds a race condition: if reschedule happens right after the up() we've won nothing and it will hang again.

Using this kind of semaphore for thread wakeup looks more dangerous everytime I think on it. down_interruptible() may be interrupted by someone with a signal and return without the semaphore locked. Better would be something like

i = down_interruptible();

if (kthread_should_stop())

	break;

if (i)

	continue;

Or we have to block all signals, then we can just ignore the _interruptible at all. What about something like this instead?

while(!kthread_should_stop()) {
	if (!down_trylock(&sem)) {
		if (kthread_should_stop())
			break;
		yield();
		continue;
	}

	/* something */
}

Eike