• Matthew Dharm's avatar
    [PATCH] USB Storage: Fix race when removing the SCSI host · bd7ae0db
    Matthew Dharm authored
    This patch fixes a race is disconnecting a usb-storage device that occurs
    with the SCSI layer.  It's primarily reproducable via adding delays into
    various disconnect and reset processing paths, but has also been
    encountered in the field.
    
    This patch started life as as281b, and was modified by me only to patch
    properly against current kernels.
    
    The main features of the patch are:
    
    	Store the host pointer at the start of the control thread
    	rather than trying to get it from srb->device; after the host
    	is removed the SCSI device structure may no longer exist.
    
    	Keep dev_semaphore locked during the entire time the control
    	thread or reset handlers are using the us_data structure.
    
    	Reorder the items in dissociate_dev() and release_resources()
    	so that things are released in the opposite order from the way
    	they were acquired originally.  Don't bother to increment and
    	decrement the usb_device's reference count; it's unnecessary.
    
    	In disconnect(), first set the DISCONNECTING flag so that no
    	more I/O will take place and no more requests will be accepted.
    	Next, cut short the current command and wait for it to finish.
    	Then call scsi_remove_host().  The SCSI core guarantees that
    	when scsi_remove_host() returns, the host will not be in error
    	recovery and all outstanding commands will have been cancelled.
    
    	Remove some old useless left-over code that was #if'ed out.
    
    	Use a wait_queue for the 6-second delay during device resets
    	so that we can be woken up in the middle if a disconnect occurs.
    
    The key point here is that after scsi_remove_host(), everything is idle as
    far as the SCSI midlayer is concerned.  But if there was a command in
    progress at the time, the midlayer will abort it without telling us or
    waiting for it to complete.  Hence we have to wait for the control thread
    to be idle before we can try to kill it.  This should happen quickly,
    since all I/O attempted by the thread will fail immediately.
    Signed-off-by: default avatarMatthew Dharm <mdharm-usb@one-eyed-alien.net>
    Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
    bd7ae0db
transport.c 36.4 KB