diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-03-02 04:51:00 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2012-03-02 04:51:00 -0500 |
commit | 62d3c5439c534b0e6c653fc63e6d8c67be3a57b1 (patch) | |
tree | d335d0e449ef2d61d52921e3f210cdd403bb025a /block/genhd.c | |
parent | cecd353a02fb1405c8a72a324b26b5acf97e7411 (diff) |
Block: use a freezable workqueue for disk-event polling
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>
CC: <stable@kernel.org>
Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/genhd.c')
-rw-r--r-- | block/genhd.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/block/genhd.c b/block/genhd.c index b26c4085590d..df9816ede75b 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -1478,9 +1478,9 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now) | |||
1478 | intv = disk_events_poll_jiffies(disk); | 1478 | intv = disk_events_poll_jiffies(disk); |
1479 | set_timer_slack(&ev->dwork.timer, intv / 4); | 1479 | set_timer_slack(&ev->dwork.timer, intv / 4); |
1480 | if (check_now) | 1480 | if (check_now) |
1481 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | 1481 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0); |
1482 | else if (intv) | 1482 | else if (intv) |
1483 | queue_delayed_work(system_nrt_wq, &ev->dwork, intv); | 1483 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv); |
1484 | out_unlock: | 1484 | out_unlock: |
1485 | spin_unlock_irqrestore(&ev->lock, flags); | 1485 | spin_unlock_irqrestore(&ev->lock, flags); |
1486 | } | 1486 | } |
@@ -1524,7 +1524,7 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask) | |||
1524 | ev->clearing |= mask; | 1524 | ev->clearing |= mask; |
1525 | if (!ev->block) { | 1525 | if (!ev->block) { |
1526 | cancel_delayed_work(&ev->dwork); | 1526 | cancel_delayed_work(&ev->dwork); |
1527 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | 1527 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0); |
1528 | } | 1528 | } |
1529 | spin_unlock_irq(&ev->lock); | 1529 | spin_unlock_irq(&ev->lock); |
1530 | } | 1530 | } |
@@ -1561,7 +1561,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask) | |||
1561 | 1561 | ||
1562 | /* uncondtionally schedule event check and wait for it to finish */ | 1562 | /* uncondtionally schedule event check and wait for it to finish */ |
1563 | disk_block_events(disk); | 1563 | disk_block_events(disk); |
1564 | queue_delayed_work(system_nrt_wq, &ev->dwork, 0); | 1564 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0); |
1565 | flush_delayed_work(&ev->dwork); | 1565 | flush_delayed_work(&ev->dwork); |
1566 | __disk_unblock_events(disk, false); | 1566 | __disk_unblock_events(disk, false); |
1567 | 1567 | ||
@@ -1598,7 +1598,7 @@ static void disk_events_workfn(struct work_struct *work) | |||
1598 | 1598 | ||
1599 | intv = disk_events_poll_jiffies(disk); | 1599 | intv = disk_events_poll_jiffies(disk); |
1600 | if (!ev->block && intv) | 1600 | if (!ev->block && intv) |
1601 | queue_delayed_work(system_nrt_wq, &ev->dwork, intv); | 1601 | queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, intv); |
1602 | 1602 | ||
1603 | spin_unlock_irq(&ev->lock); | 1603 | spin_unlock_irq(&ev->lock); |
1604 | 1604 | ||