aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorDerek Basehore <dbasehore@chromium.org>2012-12-18 15:27:18 -0500
committerJens Axboe <axboe@kernel.dk>2012-12-19 14:36:05 -0500
commitaea24a8bbc81c8b404e4e293fb37aefaf388d35d (patch)
treefc12abcaacf7c5af4c0557d68da3fad9e5879906 /block
parent74779e22261172ea728b989310f6ecc991b57d62 (diff)
block: remove deadlock in disk_clear_events
In disk_clear_events, do not put work on system_nrt_freezable_wq. Instead, put it on system_nrt_wq. There is a race between probing a usb and suspending the device. Since probing a usb calls disk_clear_events, which puts work on a frozen workqueue, probing cannot finish after the workqueue is frozen. However, suspending cannot finish until the usb probe is finished, so we get a deadlock, causing the system to reboot. The way to reproduce this bug is to wake up from suspend with a usb storage device plugged in, or plugging in a usb storage device right before suspend. The window of time is on the order of time it takes to probe the usb device. As long as the workqueues are frozen before the call to add_disk within sd_probe_async finishes, there will be a deadlock (which calls blkdev_get, sd_open, check_disk_change, then disk_clear_events). This is not difficult to reproduce after figuring out the timings. [akpm@linux-foundation.org: fix up comment] Signed-off-by: Derek Basehore <dbasehore@chromium.org> Reviewed-by: Mandeep Singh Baines <msb@chromium.org> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r--block/genhd.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/block/genhd.c b/block/genhd.c
index 9a289d7c84bb..33a3b38aa4b2 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1565,7 +1565,14 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
1565 1565
1566 /* uncondtionally schedule event check and wait for it to finish */ 1566 /* uncondtionally schedule event check and wait for it to finish */
1567 disk_block_events(disk); 1567 disk_block_events(disk);
1568 queue_delayed_work(system_freezable_wq, &ev->dwork, 0); 1568 /*
1569 * We need to put the work on system_nrt_wq here since there is a
1570 * deadlock that happens while probing a usb device while suspending. If
1571 * we put work on a freezable workqueue here, a usb probe will wait here
1572 * until the workqueue is unfrozen during suspend. Since suspend waits
1573 * on all probes to complete, we have a deadlock
1574 */
1575 queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
1569 flush_delayed_work(&ev->dwork); 1576 flush_delayed_work(&ev->dwork);
1570 __disk_unblock_events(disk, false); 1577 __disk_unblock_events(disk, false);
1571 1578