]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.2-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Mar 2012 18:55:26 +0000 (11:55 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Mar 2012 18:55:26 +0000 (11:55 -0700)
added patches:
block-use-a-freezable-workqueue-for-disk-event-polling.patch

queue-3.2/block-use-a-freezable-workqueue-for-disk-event-polling.patch [new file with mode: 0644]
queue-3.2/series

diff --git a/queue-3.2/block-use-a-freezable-workqueue-for-disk-event-polling.patch b/queue-3.2/block-use-a-freezable-workqueue-for-disk-event-polling.patch
new file mode 100644 (file)
index 0000000..a64e907
--- /dev/null
@@ -0,0 +1,122 @@
+From 62d3c5439c534b0e6c653fc63e6d8c67be3a57b1 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Fri, 2 Mar 2012 10:51:00 +0100
+Subject: Block: use a freezable workqueue for disk-event polling
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+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>
+
+---
+ block/genhd.c             |   10 +++++-----
+ include/linux/workqueue.h |    4 ++++
+ kernel/workqueue.c        |    7 ++++++-
+ 3 files changed, 15 insertions(+), 6 deletions(-)
+
+--- a/block/genhd.c
++++ b/block/genhd.c
+@@ -1479,9 +1479,9 @@ static void __disk_unblock_events(struct
+       intv = disk_events_poll_jiffies(disk);
+       set_timer_slack(&ev->dwork.timer, intv / 4);
+       if (check_now)
+-              queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
++              queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
+       else if (intv)
+-              queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
++              queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
+ out_unlock:
+       spin_unlock_irqrestore(&ev->lock, flags);
+ }
+@@ -1525,7 +1525,7 @@ void disk_flush_events(struct gendisk *d
+       ev->clearing |= mask;
+       if (!ev->block) {
+               cancel_delayed_work(&ev->dwork);
+-              queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
++              queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
+       }
+       spin_unlock_irq(&ev->lock);
+ }
+@@ -1562,7 +1562,7 @@ unsigned int disk_clear_events(struct ge
+       /* uncondtionally schedule event check and wait for it to finish */
+       disk_block_events(disk);
+-      queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
++      queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
+       flush_delayed_work(&ev->dwork);
+       __disk_unblock_events(disk, false);
+@@ -1599,7 +1599,7 @@ static void disk_events_workfn(struct wo
+       intv = disk_events_poll_jiffies(disk);
+       if (!ev->block && intv)
+-              queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
++              queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv);
+       spin_unlock_irq(&ev->lock);
+--- a/include/linux/workqueue.h
++++ b/include/linux/workqueue.h
+@@ -289,12 +289,16 @@ enum {
+  *
+  * system_freezable_wq is equivalent to system_wq except that it's
+  * freezable.
++ *
++ * system_nrt_freezable_wq is equivalent to system_nrt_wq except that
++ * it's freezable.
+  */
+ extern struct workqueue_struct *system_wq;
+ extern struct workqueue_struct *system_long_wq;
+ extern struct workqueue_struct *system_nrt_wq;
+ extern struct workqueue_struct *system_unbound_wq;
+ extern struct workqueue_struct *system_freezable_wq;
++extern struct workqueue_struct *system_nrt_freezable_wq;
+ extern struct workqueue_struct *
+ __alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -253,11 +253,13 @@ struct workqueue_struct *system_long_wq
+ struct workqueue_struct *system_nrt_wq __read_mostly;
+ struct workqueue_struct *system_unbound_wq __read_mostly;
+ struct workqueue_struct *system_freezable_wq __read_mostly;
++struct workqueue_struct *system_nrt_freezable_wq __read_mostly;
+ EXPORT_SYMBOL_GPL(system_wq);
+ EXPORT_SYMBOL_GPL(system_long_wq);
+ EXPORT_SYMBOL_GPL(system_nrt_wq);
+ EXPORT_SYMBOL_GPL(system_unbound_wq);
+ EXPORT_SYMBOL_GPL(system_freezable_wq);
++EXPORT_SYMBOL_GPL(system_nrt_freezable_wq);
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/workqueue.h>
+@@ -3821,8 +3823,11 @@ static int __init init_workqueues(void)
+                                           WQ_UNBOUND_MAX_ACTIVE);
+       system_freezable_wq = alloc_workqueue("events_freezable",
+                                             WQ_FREEZABLE, 0);
++      system_nrt_freezable_wq = alloc_workqueue("events_nrt_freezable",
++                      WQ_NON_REENTRANT | WQ_FREEZABLE, 0);
+       BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq ||
+-             !system_unbound_wq || !system_freezable_wq);
++             !system_unbound_wq || !system_freezable_wq ||
++              !system_nrt_freezable_wq);
+       return 0;
+ }
+ early_initcall(init_workqueues);
index 62f8806f7680555495ab7d60f6d1d31f7256fe4a..6775828af839040344bf7e5b713ac102292df581 100644 (file)
@@ -29,3 +29,4 @@ regulator-fix-setting-selector-in-tps6524x-set_voltage-function.patch
 block-fix-null-pointer-dereference-in-sd_revalidate_disk.patch
 block-sx8-fix-pointer-math-issue-getting-fw-version.patch
 block-fix-__blkdev_get-and-add_disk-race-condition.patch
+block-use-a-freezable-workqueue-for-disk-event-polling.patch