mirror of
https://git.yoctoproject.org/meta-ti
synced 2026-07-21 03:17:18 +00:00
7df8fc578b
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> Signed-off-by: Denys Dmytriyenko <denys@ti.com>
130 lines
4.9 KiB
Diff
130 lines
4.9 KiB
Diff
From 21816a3fe95d2536991ece0a71609d8c22f8af9d Mon Sep 17 00:00:00 2001
|
|
From: Alan Stern <stern@rowland.harvard.edu>
|
|
Date: Fri, 2 Mar 2012 10:51:00 +0100
|
|
Subject: [PATCH 32/42] Block: use a freezable workqueue for disk-event
|
|
polling
|
|
|
|
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(-)
|
|
|
|
diff --git a/block/genhd.c b/block/genhd.c
|
|
index 9db720d..997afd6 100644
|
|
--- a/block/genhd.c
|
|
+++ b/block/genhd.c
|
|
@@ -1479,9 +1479,9 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now)
|
|
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 *disk, unsigned int mask)
|
|
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 gendisk *disk, unsigned int mask)
|
|
|
|
/* 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 work_struct *work)
|
|
|
|
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);
|
|
|
|
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
|
|
index 0d556de..e228ca9 100644
|
|
--- 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,
|
|
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
|
|
index 42fa9ad..bb425b1 100644
|
|
--- a/kernel/workqueue.c
|
|
+++ b/kernel/workqueue.c
|
|
@@ -253,11 +253,13 @@ struct workqueue_struct *system_long_wq __read_mostly;
|
|
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);
|
|
--
|
|
1.7.9.4
|
|
|