diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-02-21 13:16:32 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-21 19:29:15 -0500 |
commit | bb94a406682770a35305daaa241ccdb7cab399de (patch) | |
tree | a6801c8edec8809e34c34ec889db4682f074c923 /drivers/usb/storage/usb.h | |
parent | 9a9a71b77c3fd511e5dda6236deb8a02d156b864 (diff) |
usb-storage: fix freezing of the scanning thread
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>
CC: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/storage/usb.h')
-rw-r--r-- | drivers/usb/storage/usb.h | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 7b0f2113632e..75f70f04f37b 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/blkdev.h> | 47 | #include <linux/blkdev.h> |
48 | #include <linux/completion.h> | 48 | #include <linux/completion.h> |
49 | #include <linux/mutex.h> | 49 | #include <linux/mutex.h> |
50 | #include <linux/workqueue.h> | ||
50 | #include <scsi/scsi_host.h> | 51 | #include <scsi/scsi_host.h> |
51 | 52 | ||
52 | struct us_data; | 53 | struct us_data; |
@@ -72,7 +73,7 @@ struct us_unusual_dev { | |||
72 | #define US_FLIDX_DISCONNECTING 3 /* disconnect in progress */ | 73 | #define US_FLIDX_DISCONNECTING 3 /* disconnect in progress */ |
73 | #define US_FLIDX_RESETTING 4 /* device reset in progress */ | 74 | #define US_FLIDX_RESETTING 4 /* device reset in progress */ |
74 | #define US_FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */ | 75 | #define US_FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */ |
75 | #define US_FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */ | 76 | #define US_FLIDX_SCAN_PENDING 6 /* scanning not yet done */ |
76 | #define US_FLIDX_REDO_READ10 7 /* redo READ(10) command */ | 77 | #define US_FLIDX_REDO_READ10 7 /* redo READ(10) command */ |
77 | #define US_FLIDX_READ10_WORKED 8 /* previous READ(10) succeeded */ | 78 | #define US_FLIDX_READ10_WORKED 8 /* previous READ(10) succeeded */ |
78 | 79 | ||
@@ -147,8 +148,8 @@ struct us_data { | |||
147 | /* mutual exclusion and synchronization structures */ | 148 | /* mutual exclusion and synchronization structures */ |
148 | struct completion cmnd_ready; /* to sleep thread on */ | 149 | struct completion cmnd_ready; /* to sleep thread on */ |
149 | struct completion notify; /* thread begin/end */ | 150 | struct completion notify; /* thread begin/end */ |
150 | wait_queue_head_t delay_wait; /* wait during scan, reset */ | 151 | wait_queue_head_t delay_wait; /* wait during reset */ |
151 | struct completion scanning_done; /* wait for scan thread */ | 152 | struct delayed_work scan_dwork; /* for async scanning */ |
152 | 153 | ||
153 | /* subdriver information */ | 154 | /* subdriver information */ |
154 | void *extra; /* Any extra data */ | 155 | void *extra; /* Any extra data */ |