aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/workqueue.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-03-02 04:51:00 -0500
committerLuis Henriques <luis.henriques@canonical.com>2012-03-26 05:27:06 -0400
commitc0bc7f72b9c1514484a8f5ef6ae39b636e5ba4d9 (patch)
treedfb473411b9f43d33c641bfa90c6d9ef1a6bcb24 /kernel/workqueue.c
parentb9736f1ad32476f50612411a6ea783ea469ab5ca (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.c7
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;
252struct workqueue_struct *system_nrt_wq __read_mostly; 252struct workqueue_struct *system_nrt_wq __read_mostly;
253struct workqueue_struct *system_unbound_wq __read_mostly; 253struct workqueue_struct *system_unbound_wq __read_mostly;
254struct workqueue_struct *system_freezable_wq __read_mostly; 254struct workqueue_struct *system_freezable_wq __read_mostly;
255struct workqueue_struct *system_nrt_freezable_wq __read_mostly;
255EXPORT_SYMBOL_GPL(system_wq); 256EXPORT_SYMBOL_GPL(system_wq);
256EXPORT_SYMBOL_GPL(system_long_wq); 257EXPORT_SYMBOL_GPL(system_long_wq);
257EXPORT_SYMBOL_GPL(system_nrt_wq); 258EXPORT_SYMBOL_GPL(system_nrt_wq);
258EXPORT_SYMBOL_GPL(system_unbound_wq); 259EXPORT_SYMBOL_GPL(system_unbound_wq);
259EXPORT_SYMBOL_GPL(system_freezable_wq); 260EXPORT_SYMBOL_GPL(system_freezable_wq);
261EXPORT_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}
3803early_initcall(init_workqueues); 3808early_initcall(init_workqueues);