From 3856e548372513665670ca5db60d9a74b970fe0d Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Thu, 11 Sep 2014 22:20:39 +0930 Subject: virtio-rng: fix stuck of hot-unplugging busy device When we try to hot-remove a busy virtio-rng device from QEMU monitor, the device can't be hot-removed. Because virtio-rng driver hangs at wait_for_completion_killable(). This patch exits the waiting by completing have_data completion before unregistering, resets data_avail to avoid the hwrng core use wrong buffer bytes. Signed-off-by: Amos Kong Reviewed-by: Amit Shah Cc: stable@vger.kernel.org Signed-off-by: Rusty Russell --- drivers/char/hw_random/virtio-rng.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 2e3139eda93b..849b22877196 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -137,6 +137,8 @@ static void remove_common(struct virtio_device *vdev) { struct virtrng_info *vi = vdev->priv; + vi->data_avail = 0; + complete(&vi->have_data); vdev->config->reset(vdev); vi->busy = false; if (vi->hwrng_register_done) -- cgit v1.2.3-59-g8ed1b From f49819560f53b7f3a596a8ea2e6764dc86695b62 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Thu, 11 Sep 2014 22:21:53 +0930 Subject: virtio-rng: skip reading when we start to remove the device Before we really unregister the hwrng device, reading will get stuck if the virtio device is reset. We should return error for reading when we start to remove the device. Signed-off-by: Amos Kong Reviewed-by: Amit Shah Cc: stable@vger.kernel.org Signed-off-by: Rusty Russell --- drivers/char/hw_random/virtio-rng.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/char') diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 849b22877196..132c9ccfdc62 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -36,6 +36,7 @@ struct virtrng_info { int index; bool busy; bool hwrng_register_done; + bool hwrng_removed; }; @@ -68,6 +69,9 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) int ret; struct virtrng_info *vi = (struct virtrng_info *)rng->priv; + if (vi->hwrng_removed) + return -ENODEV; + if (!vi->busy) { vi->busy = true; init_completion(&vi->have_data); @@ -137,6 +141,7 @@ static void remove_common(struct virtio_device *vdev) { struct virtrng_info *vi = vdev->priv; + vi->hwrng_removed = true; vi->data_avail = 0; complete(&vi->have_data); vdev->config->reset(vdev); -- cgit v1.2.3-59-g8ed1b