diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-03-02 04:51:00 -0500 |
---|---|---|
committer | Luis Henriques <luis.henriques@canonical.com> | 2012-03-26 05:27:06 -0400 |
commit | c0bc7f72b9c1514484a8f5ef6ae39b636e5ba4d9 (patch) | |
tree | dfb473411b9f43d33c641bfa90c6d9ef1a6bcb24 /kernel/workqueue.c | |
parent | b9736f1ad32476f50612411a6ea783ea469ab5ca (diff) |
Block: use a freezable workqueue for disk-event polling
BugLink: http://bugs.launchpad.net/bugs/959470
commit 62d3c5439c534b0e6c653fc63e6d8c67be3a57b1 upstream.
This patch (as1519) fixes a bug in the block layer's disk-events
polling. The polling is done by a work routine queued on the
system_nrt_wq workqueue. Since that workqueue isn't freezable, the
polling continues even in the middle of a system sleep transition.
Obviously, polling a suspended drive for media changes and such isn't
a good thing to do; in the case of USB mass-storage devices it can
lead to real problems requiring device resets and even re-enumeration.
The patch fixes things by creating a new system-wide, non-reentrant,
freezable workqueue and using it for disk-events polling.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index aec02b6a1c4..1456daba9a0 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -252,11 +252,13 @@ struct workqueue_struct *system_long_wq __read_mostly; | |||
252 | struct workqueue_struct *system_nrt_wq __read_mostly; | 252 | struct workqueue_struct *system_nrt_wq __read_mostly; |
253 | struct workqueue_struct *system_unbound_wq __read_mostly; | 253 | struct workqueue_struct *system_unbound_wq __read_mostly; |
254 | struct workqueue_struct *system_freezable_wq __read_mostly; | 254 | struct workqueue_struct *system_freezable_wq __read_mostly; |
255 | struct workqueue_struct *system_nrt_freezable_wq __read_mostly; | ||
255 | EXPORT_SYMBOL_GPL(system_wq); | 256 | EXPORT_SYMBOL_GPL(system_wq); |
256 | EXPORT_SYMBOL_GPL(system_long_wq); | 257 | EXPORT_SYMBOL_GPL(system_long_wq); |
257 | EXPORT_SYMBOL_GPL(system_nrt_wq); | 258 | EXPORT_SYMBOL_GPL(system_nrt_wq); |
258 | EXPORT_SYMBOL_GPL(system_unbound_wq); | 259 | EXPORT_SYMBOL_GPL(system_unbound_wq); |
259 | EXPORT_SYMBOL_GPL(system_freezable_wq); | 260 | EXPORT_SYMBOL_GPL(system_freezable_wq); |
261 | EXPORT_SYMBOL_GPL(system_nrt_freezable_wq); | ||
260 | 262 | ||
261 | #define CREATE_TRACE_POINTS | 263 | #define CREATE_TRACE_POINTS |
262 | #include <trace/events/workqueue.h> | 264 | #include <trace/events/workqueue.h> |
@@ -3796,8 +3798,11 @@ static int __init init_workqueues(void) | |||
3796 | WQ_UNBOUND_MAX_ACTIVE); | 3798 | WQ_UNBOUND_MAX_ACTIVE); |
3797 | system_freezable_wq = alloc_workqueue("events_freezable", | 3799 | system_freezable_wq = alloc_workqueue("events_freezable", |
3798 | WQ_FREEZABLE, 0); | 3800 | WQ_FREEZABLE, 0); |
3801 | system_nrt_freezable_wq = alloc_workqueue("events_nrt_freezable", | ||
3802 | WQ_NON_REENTRANT | WQ_FREEZABLE, 0); | ||
3799 | BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq || | 3803 | BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq || |
3800 | !system_unbound_wq || !system_freezable_wq); | 3804 | !system_unbound_wq || !system_freezable_wq || |
3805 | !system_nrt_freezable_wq); | ||
3801 | return 0; | 3806 | return 0; |
3802 | } | 3807 | } |
3803 | early_initcall(init_workqueues); | 3808 | early_initcall(init_workqueues); |