-
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: Matthew Dharm <mdharm-usb@one-eyed-alien.net> Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
bd7ae0db