ChangeSet 1.2181.4.61, 2005/03/24 15:13:36-08:00, [EMAIL PROTECTED]

        [PATCH] USB Storage: allow disconnect to complete faster
        
        This patch started life as as476 from Alan Stern.  It has been rediffed
        against the tip, tho that was a few days ago.
        
        This patch makes the disconnect() routine not wait for the control and
        scanning threads to exit.  This may not seem important now, but it will
        become important later: We would end up with a deadlock if disconnect()
        (which is called with the device locked) was waiting for the control
        thread to exit, while the control thread was waiting to lock the device 
so
        it could do an autosuspend.
        
        It's necessary to make sure that the host and us_data structures aren't
        deallocated before the control and scanning threads are through with 
them.
        This is done by calling scsi_host_get and scsi_host_put at the start and
        end of each thread, before signalling that the threads are running.  
Since
        the probe() and disconnect() routines cannot run concurrently 
(guaranteed
        to us by the USB core), this method will guarantee the structures are 
not
        deallocated too soon.
        
        While there's nothing wrong with leaving the threads alive after
        disconnect() returns, there would be a real problem if the threads were
        still alive when usb_stor_exit returned!  So now usb_stor_exit has to 
wait
        to make sure all the threads have died.  Apparently the only safe way 
for
        one thread to signal another while exiting is to use complete_and_exit,
        which we've been doing.  So the patch adds a new driver-wide struct
        completion, named threads_gone, and each thread signals it while 
exiting.
        usb_stor_exit must call wait_for_completion the appropriate number of
        times, and that number is stored in a new counter named total_threads.
        
        
        Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
        Signed-off-by: Matthew Dharm <[EMAIL PROTECTED]>
        Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>



 usb.c |   48 +++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 41 insertions(+), 7 deletions(-)


diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c 2005-03-30 15:17:06 -08:00
+++ b/drivers/usb/storage/usb.c 2005-03-30 15:17:06 -08:00
@@ -102,6 +102,13 @@
 MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
 
 
+/* These are used to make sure the module doesn't unload before all the
+ * threads have exited.
+ */
+static atomic_t total_threads = ATOMIC_INIT(0);
+static DECLARE_COMPLETION(threads_gone);
+
+
 static int storage_probe(struct usb_interface *iface,
                         const struct usb_device_id *id);
 
@@ -286,11 +293,13 @@
         * so get rid of all our resources.
         */
        daemonize("usb-storage");
-
        current->flags |= PF_NOFREEZE;
-
        unlock_kernel();
 
+       /* acquire a reference to the host, so it won't be deallocated
+        * until we're ready to exit */
+       scsi_host_get(host);
+
        /* signal that we've started the thread */
        complete(&(us->notify));
 
@@ -394,6 +403,8 @@
                up(&(us->dev_semaphore));
        } /* for (;;) */
 
+       scsi_host_put(host);
+
        /* notify the exit routine that we're actually exiting now 
         *
         * complete()/wait_for_completion() is similar to up()/down(),
@@ -408,7 +419,7 @@
         * This is important in preemption kernels, which transfer the flow
         * of execution immediately upon a complete().
         */
-       complete_and_exit(&(us->notify), 0);
+       complete_and_exit(&threads_gone, 0);
 }      
 
 /***********************************************************************
@@ -757,6 +768,7 @@
                return p;
        }
        us->pid = p;
+       atomic_inc(&total_threads);
 
        /* Wait for the thread to start */
        wait_for_completion(&(us->notify));
@@ -817,6 +829,13 @@
        daemonize("usb-stor-scan");
        unlock_kernel();
 
+       /* Acquire a reference to the host, so it won't be deallocated
+        * until we're ready to exit */
+       scsi_host_get(us_to_host(us));
+
+       /* Signal that we've started the thread */
+       complete(&(us->notify));
+
        printk(KERN_DEBUG
                "usb-storage: device found at %d\n", us->pusb_dev->devnum);
 
@@ -838,9 +857,12 @@
        if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
                scsi_scan_host(us_to_host(us));
                printk(KERN_DEBUG "usb-storage: device scan complete\n");
+
+               /* Should we unbind if no devices were detected? */
        }
 
-       complete_and_exit(&us->scsi_scan_done, 0);
+       scsi_host_put(us_to_host(us));
+       complete_and_exit(&threads_gone, 0);
 }
 
 
@@ -941,6 +963,10 @@
                scsi_remove_host(host);
                goto BadDevice;
        }
+       atomic_inc(&total_threads);
+
+       /* Wait for the thread to start */
+       wait_for_completion(&(us->notify));
 
        return 0;
 
@@ -967,10 +993,8 @@
        usb_stor_stop_transport(us);
        wake_up(&us->dev_reset_wait);
 
-       /* Interrupt the SCSI-device-scanning thread's time delay, and
-        * wait for the thread to finish */
+       /* Interrupt the SCSI-device-scanning thread's time delay */
        wake_up(&us->scsi_scan_wait);
-       wait_for_completion(&us->scsi_scan_done);
 
        /* Wait for the current command to finish, then remove the host */
        down(&us->dev_semaphore);
@@ -1013,6 +1037,16 @@
         */
        US_DEBUGP("-- calling usb_deregister()\n");
        usb_deregister(&usb_storage_driver) ;
+
+       /* Don't return until all of our control and scanning threads
+        * have exited.  Since each thread signals threads_gone as its
+        * last act, we have to call wait_for_completion the right number
+        * of times.
+        */
+       while (atomic_read(&total_threads) > 0) {
+               wait_for_completion(&threads_gone);
+               atomic_dec(&total_threads);
+       }
 }
 
 module_init(usb_stor_init);
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to