From: Jens Axboe Following some consideration, I think it's better to simply always invoke the request_fn even if the device wasn't plugged if someone unplugs it. This solves the problem of md + dm setting the plugged bit unconditionally _outside_ of the queue lock, thus confusing some drivers that checks this bit for sanity in the request_fn. --- /dev/null | 0 25-akpm/drivers/block/ll_rw_blk.c | 2 +- 25-akpm/drivers/md/dm.c | 1 - 25-akpm/drivers/md/md.c | 5 +---- drivers/md/dm-table.c | 0 5 files changed, 2 insertions(+), 6 deletions(-) diff -puN drivers/block/ll_rw_blk.c~per-backing_dev-unplugging-dm-md-rethink drivers/block/ll_rw_blk.c --- 25/drivers/block/ll_rw_blk.c~per-backing_dev-unplugging-dm-md-rethink 2004-03-17 02:23:34.770201872 -0800 +++ 25-akpm/drivers/block/ll_rw_blk.c 2004-03-17 02:24:29.705850384 -0800 @@ -1138,7 +1138,7 @@ static inline void __generic_unplug_devi * always call down, since we can race now with setting the plugged * bit outside of the queue lock */ - (void) blk_remove_plug(q); + blk_remove_plug(q); /* * was plugged, fire request_fn if queue has stuff to do diff -puN drivers/md/dm.c~per-backing_dev-unplugging-dm-md-rethink drivers/md/dm.c --- 25/drivers/md/dm.c~per-backing_dev-unplugging-dm-md-rethink 2004-03-17 02:23:34.772201568 -0800 +++ 25-akpm/drivers/md/dm.c 2004-03-17 02:23:34.784199744 -0800 @@ -580,7 +580,6 @@ static void dm_unplug_all(request_queue_ struct mapped_device *md = q->queuedata; struct dm_table *map = dm_get_table(md); - clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); if (map) { dm_table_unplug_all(map); dm_table_put(map); diff -puN drivers/md/dm-table.c~per-backing_dev-unplugging-dm-md-rethink drivers/md/dm-table.c diff -puN drivers/md/md.c~per-backing_dev-unplugging-dm-md-rethink drivers/md/md.c --- 25/drivers/md/md.c~per-backing_dev-unplugging-dm-md-rethink 2004-03-17 02:23:34.776200960 -0800 +++ 25-akpm/drivers/md/md.c 2004-03-17 02:23:37.173836464 -0800 @@ -171,10 +171,8 @@ void md_unplug_mddev(mddev_t *mddev) ITERATE_RDEV(mddev, rdev, tmp) { request_queue_t *r_queue = bdev_get_queue(rdev->bdev); - if (r_queue->unplug_fn) { - set_bit(QUEUE_FLAG_PLUGGED, &r_queue->queue_flags); + if (r_queue->unplug_fn) r_queue->unplug_fn(r_queue); - } } } EXPORT_SYMBOL(md_unplug_mddev); @@ -183,7 +181,6 @@ static void md_unplug_all(request_queue_ { mddev_t *mddev = q->queuedata; - clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); md_unplug_mddev(mddev); } diff -puN -L opt/kernel/linux-2.6.5-rc1-mm1/drivers/block/ll_rw_blk.c /dev/null /dev/null diff -puN -L opt/kernel/linux-2.6.5-rc1-mm1/drivers/md/dm.c /dev/null /dev/null diff -puN -L opt/kernel/linux-2.6.5-rc1-mm1/drivers/md/dm-table.c /dev/null /dev/null diff -puN -L opt/kernel/linux-2.6.5-rc1-mm1/drivers/md/md.c /dev/null /dev/null _