From: Greg Kroah-Hartman Date: Thu, 15 Mar 2012 18:55:26 +0000 (-0700) Subject: 3.2-stable patches X-Git-Tag: v3.0.25~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c5cd2ffd3f88ddfcb7873903c129fae71fb8f71f;p=thirdparty%2Fkernel%2Fstable-queue.git 3.2-stable patches added patches: block-use-a-freezable-workqueue-for-disk-event-polling.patch --- 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 index 00000000000..a64e907079b --- /dev/null +++ b/queue-3.2/block-use-a-freezable-workqueue-for-disk-event-polling.patch @@ -0,0 +1,122 @@ +From 62d3c5439c534b0e6c653fc63e6d8c67be3a57b1 Mon Sep 17 00:00:00 2001 +From: Alan Stern +Date: Fri, 2 Mar 2012 10:51:00 +0100 +Subject: Block: use a freezable workqueue for disk-event polling + +From: Alan Stern + +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 +Acked-by: Tejun Heo +Acked-by: Rafael J. Wysocki +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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 +@@ -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); diff --git a/queue-3.2/series b/queue-3.2/series index 62f8806f768..6775828af83 100644 --- a/queue-3.2/series +++ b/queue-3.2/series @@ -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