From: Jens Axboe At SUSE I reproduced a problem with dm and ide disks on a 4-way where ide request_fn would discover the queue plugged all of a sudden, and then give up on doing io. The problem is due to the fact that dm now sets QUEUE_FLAG_PLUGGED without holding the target queue lock. I think the best fix is simply not to set the PLUGGED bit outside of the queue lock, and just let __generic_unplug_device() always call down into the request_fn() even if the queue wasn't plugged. This should be a very rare occurence. --- 25-akpm/drivers/block/ll_rw_blk.c | 7 +++++-- 25-akpm/drivers/md/dm-table.c | 4 +--- 2 files changed, 6 insertions(+), 5 deletions(-) diff -puN drivers/block/ll_rw_blk.c~per-backing_dev-unplugging-dm-fix drivers/block/ll_rw_blk.c --- 25/drivers/block/ll_rw_blk.c~per-backing_dev-unplugging-dm-fix 2004-03-16 13:17:49.754333688 -0800 +++ 25-akpm/drivers/block/ll_rw_blk.c 2004-03-16 13:17:49.760332776 -0800 @@ -1134,8 +1134,11 @@ static inline void __generic_unplug_devi if (test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) return; - if (!blk_remove_plug(q)) - return; + /* + * always call down, since we can race now with setting the plugged + * bit outside of the queue lock + */ + (void) blk_remove_plug(q); /* * was plugged, fire request_fn if queue has stuff to do diff -puN drivers/md/dm-table.c~per-backing_dev-unplugging-dm-fix drivers/md/dm-table.c --- 25/drivers/md/dm-table.c~per-backing_dev-unplugging-dm-fix 2004-03-16 13:17:49.755333536 -0800 +++ 25-akpm/drivers/md/dm-table.c 2004-03-16 13:17:49.761332624 -0800 @@ -893,10 +893,8 @@ void dm_table_unplug_all(struct dm_table struct dm_dev *dd = list_entry(d, struct dm_dev, list); request_queue_t *q = bdev_get_queue(dd->bdev); - if (q->unplug_fn) { - set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); + if (q->unplug_fn) q->unplug_fn(q); - } } } _