diff options
Diffstat (limited to 'drivers/usb/storage')
| -rw-r--r-- | drivers/usb/storage/usb.c | 90 | ||||
| -rw-r--r-- | drivers/usb/storage/usb.h | 7 | 
2 files changed, 35 insertions, 62 deletions
| diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 3dd7da9fd50..db51ba16dc0 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -788,15 +788,19 @@ static void quiesce_and_remove_host(struct us_data *us)  	struct Scsi_Host *host = us_to_host(us);  	/* If the device is really gone, cut short reset delays */ -	if (us->pusb_dev->state == USB_STATE_NOTATTACHED) +	if (us->pusb_dev->state == USB_STATE_NOTATTACHED) {  		set_bit(US_FLIDX_DISCONNECTING, &us->dflags); +		wake_up(&us->delay_wait); +	} -	/* Prevent SCSI-scanning (if it hasn't started yet) -	 * and wait for the SCSI-scanning thread to stop. +	/* Prevent SCSI scanning (if it hasn't started yet) +	 * or wait for the SCSI-scanning routine to stop.  	 */ -	set_bit(US_FLIDX_DONT_SCAN, &us->dflags); -	wake_up(&us->delay_wait); -	wait_for_completion(&us->scanning_done); +	cancel_delayed_work_sync(&us->scan_dwork); + +	/* Balance autopm calls if scanning was cancelled */ +	if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags)) +		usb_autopm_put_interface_no_suspend(us->pusb_intf);  	/* Removing the host will perform an orderly shutdown: caches  	 * synchronized, disks spun down, etc. @@ -823,53 +827,28 @@ static void release_everything(struct us_data *us)  	scsi_host_put(us_to_host(us));  } -/* Thread to carry out delayed SCSI-device scanning */ -static int usb_stor_scan_thread(void * __us) +/* Delayed-work routine to carry out SCSI-device scanning */ +static void usb_stor_scan_dwork(struct work_struct *work)  { -	struct us_data *us = (struct us_data *)__us; +	struct us_data *us = container_of(work, struct us_data, +			scan_dwork.work);  	struct device *dev = &us->pusb_intf->dev; -	dev_dbg(dev, "device found\n"); - -	set_freezable(); +	dev_dbg(dev, "starting scan\n"); -	/* -	 * Wait for the timeout to expire or for a disconnect -	 * -	 * We can't freeze in this thread or we risk causing khubd to -	 * fail to freeze, but we can't be non-freezable either. Nor can -	 * khubd freeze while waiting for scanning to complete as it may -	 * hold the device lock, causing a hang when suspending devices. -	 * So instead of using wait_event_freezable(), explicitly test -	 * for (DONT_SCAN || freezing) in interruptible wait and proceed -	 * if any of DONT_SCAN, freezing or timeout has happened. -	 */ -	if (delay_use > 0) { -		dev_dbg(dev, "waiting for device to settle " -				"before scanning\n"); -		wait_event_interruptible_timeout(us->delay_wait, -				test_bit(US_FLIDX_DONT_SCAN, &us->dflags) || -				freezing(current), delay_use * HZ); +	/* For bulk-only devices, determine the max LUN value */ +	if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) { +		mutex_lock(&us->dev_mutex); +		us->max_lun = usb_stor_Bulk_max_lun(us); +		mutex_unlock(&us->dev_mutex);  	} +	scsi_scan_host(us_to_host(us)); +	dev_dbg(dev, "scan complete\n"); -	/* If the device is still connected, perform the scanning */ -	if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) { - -		/* For bulk-only devices, determine the max LUN value */ -		if (us->protocol == USB_PR_BULK && -				!(us->fflags & US_FL_SINGLE_LUN)) { -			mutex_lock(&us->dev_mutex); -			us->max_lun = usb_stor_Bulk_max_lun(us); -			mutex_unlock(&us->dev_mutex); -		} -		scsi_scan_host(us_to_host(us)); -		dev_dbg(dev, "scan complete\n"); - -		/* Should we unbind if no devices were detected? */ -	} +	/* Should we unbind if no devices were detected? */  	usb_autopm_put_interface(us->pusb_intf); -	complete_and_exit(&us->scanning_done, 0); +	clear_bit(US_FLIDX_SCAN_PENDING, &us->dflags);  }  static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf) @@ -916,7 +895,7 @@ int usb_stor_probe1(struct us_data **pus,  	init_completion(&us->cmnd_ready);  	init_completion(&(us->notify));  	init_waitqueue_head(&us->delay_wait); -	init_completion(&us->scanning_done); +	INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork);  	/* Associate the us_data structure with the USB device */  	result = associate_dev(us, intf); @@ -947,7 +926,6 @@ EXPORT_SYMBOL_GPL(usb_stor_probe1);  /* Second part of general USB mass-storage probing */  int usb_stor_probe2(struct us_data *us)  { -	struct task_struct *th;  	int result;  	struct device *dev = &us->pusb_intf->dev; @@ -988,20 +966,14 @@ int usb_stor_probe2(struct us_data *us)  		goto BadDevice;  	} -	/* Start up the thread for delayed SCSI-device scanning */ -	th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan"); -	if (IS_ERR(th)) { -		dev_warn(dev, -				"Unable to start the device-scanning thread\n"); -		complete(&us->scanning_done); -		quiesce_and_remove_host(us); -		result = PTR_ERR(th); -		goto BadDevice; -	} - +	/* Submit the delayed_work for SCSI-device scanning */  	usb_autopm_get_interface_no_resume(us->pusb_intf); -	wake_up_process(th); +	set_bit(US_FLIDX_SCAN_PENDING, &us->dflags); +	if (delay_use > 0) +		dev_dbg(dev, "waiting for device to settle before scanning\n"); +	queue_delayed_work(system_freezable_wq, &us->scan_dwork, +			delay_use * HZ);  	return 0;  	/* We come here if there are any problems */ diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 7b0f2113632..75f70f04f37 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -47,6 +47,7 @@  #include <linux/blkdev.h>  #include <linux/completion.h>  #include <linux/mutex.h> +#include <linux/workqueue.h>  #include <scsi/scsi_host.h>  struct us_data; @@ -72,7 +73,7 @@ struct us_unusual_dev {  #define US_FLIDX_DISCONNECTING	3	/* disconnect in progress   */  #define US_FLIDX_RESETTING	4	/* device reset in progress */  #define US_FLIDX_TIMED_OUT	5	/* SCSI midlayer timed out  */ -#define US_FLIDX_DONT_SCAN	6	/* don't scan (disconnect)  */ +#define US_FLIDX_SCAN_PENDING	6	/* scanning not yet done    */  #define US_FLIDX_REDO_READ10	7	/* redo READ(10) command    */  #define US_FLIDX_READ10_WORKED	8	/* previous READ(10) succeeded */ @@ -147,8 +148,8 @@ struct us_data {  	/* mutual exclusion and synchronization structures */  	struct completion	cmnd_ready;	 /* to sleep thread on	    */  	struct completion	notify;		 /* thread begin/end	    */ -	wait_queue_head_t	delay_wait;	 /* wait during scan, reset */ -	struct completion	scanning_done;	 /* wait for scan thread    */ +	wait_queue_head_t	delay_wait;	 /* wait during reset	    */ +	struct delayed_work	scan_dwork;	 /* for async scanning      */  	/* subdriver information */  	void			*extra;		 /* Any extra data          */ | 
