--- /dev/null
+From bb94a406682770a35305daaa241ccdb7cab399de Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 21 Feb 2012 13:16:32 -0500
+Subject: usb-storage: fix freezing of the scanning thread
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit bb94a406682770a35305daaa241ccdb7cab399de upstream.
+
+This patch (as1521b) fixes the interaction between usb-storage's
+scanning thread and the freezer. The current implementation has a
+race: If the device is unplugged shortly after being plugged in and
+just as a system sleep begins, the scanning thread may get frozen
+before the khubd task. Khubd won't be able to freeze until the
+disconnect processing is complete, and the disconnect processing can't
+proceed until the scanning thread finishes, so the sleep transition
+will fail.
+
+The implementation in the 3.2 kernel suffers from an additional
+problem. There the scanning thread calls set_freezable_with_signal(),
+and the signals sent by the freezer will mess up the thread's I/O
+delays, which are all interruptible.
+
+The solution to both problems is the same: Replace the kernel thread
+used for scanning with a delayed-work routine on the system freezable
+work queue. Freezable work queues have the nice property that you can
+cancel a work item even while the work queue is frozen, and no signals
+are needed.
+
+The 3.2 version of this patch solves the problem in Bugzilla #42730.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Acked-by: Seth Forshee <seth.forshee@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/storage/usb.c | 91 ++++++++++++++++------------------------------
+ drivers/usb/storage/usb.h | 7 ++-
+ 2 files changed, 36 insertions(+), 62 deletions(-)
+
+--- a/drivers/usb/storage/usb.c
++++ b/drivers/usb/storage/usb.c
+@@ -788,15 +788,19 @@ static void quiesce_and_remove_host(stru
+ 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,52 +827,28 @@ static void release_everything(struct 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_with_signal();
+- /*
+- * 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 we request a fake signal when freezing and use
+- * interruptible sleep to kick us out of our wait early when
+- * freezing happens.
+- */
+- 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),
+- delay_use * HZ);
+- }
+-
+- /* 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");
++ dev_dbg(dev, "starting scan\n");
+
+- /* Should we unbind if no devices were detected? */
++ /* 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? */
+
+ 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)
+@@ -915,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);
+@@ -946,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;
+
+@@ -987,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 */
+--- 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 */