Commit 483001c7 authored by Asias He's avatar Asias He Committed by Rusty Russell

virtio-blk: Reset device after blk_cleanup_queue()

blk_cleanup_queue() will call blk_drian_queue() to drain all the
requests before queue DEAD marking. If we reset the device before
blk_cleanup_queue() the drain would fail.

1) if the queue is stopped in do_virtblk_request() because device is
full, the q->request_fn() will not be called.

blk_drain_queue() {
   while(true) {
      ...
      if (!list_empty(&q->queue_head))
        __blk_run_queue(q) {
	    if (queue is not stoped)
		q->request_fn()
	}
      ...
   }
}

Do no reset the device before blk_cleanup_queue() gives the chance to
start the queue in interrupt handler blk_done().

2) In commit b79d866c, We abort requests
dispatched to driver before blk_cleanup_queue(). There is a race if
requests are dispatched to driver after the abort and before the queue
DEAD mark. To fix this, instead of aborting the requests explicitly, we
can just reset the device after after blk_cleanup_queue so that the
device can complete all the requests before queue DEAD marking in the
drain process.

Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: virtualization@lists.linux-foundation.org
Cc: kvm@vger.kernel.org
Cc: stable@kernel.org
Signed-off-by: default avatarAsias He <asias@redhat.com>
Acked-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 02e2b124
...@@ -576,8 +576,6 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) ...@@ -576,8 +576,6 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
{ {
struct virtio_blk *vblk = vdev->priv; struct virtio_blk *vblk = vdev->priv;
int index = vblk->index; int index = vblk->index;
struct virtblk_req *vbr;
unsigned long flags;
/* Prevent config work handler from accessing the device. */ /* Prevent config work handler from accessing the device. */
mutex_lock(&vblk->config_lock); mutex_lock(&vblk->config_lock);
...@@ -585,21 +583,13 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) ...@@ -585,21 +583,13 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
mutex_unlock(&vblk->config_lock); mutex_unlock(&vblk->config_lock);
del_gendisk(vblk->disk); del_gendisk(vblk->disk);
blk_cleanup_queue(vblk->disk->queue);
/* Stop all the virtqueues. */ /* Stop all the virtqueues. */
vdev->config->reset(vdev); vdev->config->reset(vdev);
flush_work(&vblk->config_work); flush_work(&vblk->config_work);
/* Abort requests dispatched to driver. */
spin_lock_irqsave(&vblk->lock, flags);
while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) {
__blk_end_request_all(vbr->req, -EIO);
mempool_free(vbr, vblk->pool);
}
spin_unlock_irqrestore(&vblk->lock, flags);
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk); put_disk(vblk->disk);
mempool_destroy(vblk->pool); mempool_destroy(vblk->pool);
vdev->config->del_vqs(vdev); vdev->config->del_vqs(vdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment