]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
hwrng: virtio - always add a pending request
authorLaurent Vivier <lvivier@redhat.com>
Thu, 28 Oct 2021 10:11:11 +0000 (12:11 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jul 2023 06:37:17 +0000 (08:37 +0200)
[ Upstream commit 9a4b612d675b03f7fc9fa1957ca399c8223f3954 ]

If we ensure we have already some data available by enqueuing
again the buffer once data are exhausted, we can return what we
have without waiting for the device answer.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Link: https://lore.kernel.org/r/20211028101111.128049-5-lvivier@redhat.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Stable-dep-of: ac52578d6e8d ("hwrng: virtio - Fix race on data_avail and actual data")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/char/hw_random/virtio-rng.c

index 207a5f3b335c08941dd6a97253241cfff5e8cad5..f98e3ee5f8b0307feca826be2b61bf90322b6c75 100644 (file)
@@ -19,7 +19,6 @@ struct virtrng_info {
        struct virtqueue *vq;
        char name[25];
        int index;
-       bool busy;
        bool hwrng_register_done;
        bool hwrng_removed;
        /* data transfer */
@@ -43,16 +42,18 @@ static void random_recv_done(struct virtqueue *vq)
                return;
 
        vi->data_idx = 0;
-       vi->busy = false;
 
        complete(&vi->have_data);
 }
 
-/* The host will fill any buffer we give it with sweet, sweet randomness. */
-static void register_buffer(struct virtrng_info *vi)
+static void request_entropy(struct virtrng_info *vi)
 {
        struct scatterlist sg;
 
+       reinit_completion(&vi->have_data);
+       vi->data_avail = 0;
+       vi->data_idx = 0;
+
        sg_init_one(&sg, vi->data, sizeof(vi->data));
 
        /* There should always be room for one buffer. */
@@ -68,6 +69,8 @@ static unsigned int copy_data(struct virtrng_info *vi, void *buf,
        memcpy(buf, vi->data + vi->data_idx, size);
        vi->data_idx += size;
        vi->data_avail -= size;
+       if (vi->data_avail == 0)
+               request_entropy(vi);
        return size;
 }
 
@@ -97,13 +100,7 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
         * so either size is 0 or data_avail is 0
         */
        while (size != 0) {
-               /* data_avail is 0 */
-               if (!vi->busy) {
-                       /* no pending request, ask for more */
-                       vi->busy = true;
-                       reinit_completion(&vi->have_data);
-                       register_buffer(vi);
-               }
+               /* data_avail is 0 but a request is pending */
                ret = wait_for_completion_killable(&vi->have_data);
                if (ret < 0)
                        return ret;
@@ -125,8 +122,7 @@ static void virtio_cleanup(struct hwrng *rng)
 {
        struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
 
-       if (vi->busy)
-               complete(&vi->have_data);
+       complete(&vi->have_data);
 }
 
 static int probe_common(struct virtio_device *vdev)
@@ -162,6 +158,9 @@ static int probe_common(struct virtio_device *vdev)
                goto err_find;
        }
 
+       /* we always have a pending entropy request */
+       request_entropy(vi);
+
        return 0;
 
 err_find:
@@ -180,7 +179,6 @@ static void remove_common(struct virtio_device *vdev)
        vi->data_idx = 0;
        complete(&vi->have_data);
        vdev->config->reset(vdev);
-       vi->busy = false;
        if (vi->hwrng_register_done)
                hwrng_unregister(&vi->hwrng);
        vdev->config->del_vqs(vdev);