Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bdc0580d authored by Laurent Vivier's avatar Laurent Vivier Committed by Greg Kroah-Hartman
Browse files

hwrng: virtio - always add a pending request



[ 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: default avatarLaurent Vivier <lvivier@redhat.com>
Link: https://lore.kernel.org/r/20211028101111.128049-5-lvivier@redhat.com


Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Stable-dep-of: ac52578d6e8d ("hwrng: virtio - Fix race on data_avail and actual data")
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent b2add016
Loading
Loading
Loading
Loading
+12 −14
Original line number Original line Diff line number Diff line
@@ -32,7 +32,6 @@ struct virtrng_info {
	struct virtqueue *vq;
	struct virtqueue *vq;
	char name[25];
	char name[25];
	int index;
	int index;
	bool busy;
	bool hwrng_register_done;
	bool hwrng_register_done;
	bool hwrng_removed;
	bool hwrng_removed;
	/* data transfer */
	/* data transfer */
@@ -56,16 +55,18 @@ static void random_recv_done(struct virtqueue *vq)
		return;
		return;


	vi->data_idx = 0;
	vi->data_idx = 0;
	vi->busy = false;


	complete(&vi->have_data);
	complete(&vi->have_data);
}
}


/* The host will fill any buffer we give it with sweet, sweet randomness. */
static void request_entropy(struct virtrng_info *vi)
static void register_buffer(struct virtrng_info *vi)
{
{
	struct scatterlist sg;
	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));
	sg_init_one(&sg, vi->data, sizeof(vi->data));


	/* There should always be room for one buffer. */
	/* There should always be room for one buffer. */
@@ -81,6 +82,8 @@ static unsigned int copy_data(struct virtrng_info *vi, void *buf,
	memcpy(buf, vi->data + vi->data_idx, size);
	memcpy(buf, vi->data + vi->data_idx, size);
	vi->data_idx += size;
	vi->data_idx += size;
	vi->data_avail -= size;
	vi->data_avail -= size;
	if (vi->data_avail == 0)
		request_entropy(vi);
	return size;
	return size;
}
}


@@ -110,13 +113,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
	 * so either size is 0 or data_avail is 0
	 */
	 */
	while (size != 0) {
	while (size != 0) {
		/* data_avail is 0 */
		/* data_avail is 0 but a request is pending */
		if (!vi->busy) {
			/* no pending request, ask for more */
			vi->busy = true;
			reinit_completion(&vi->have_data);
			register_buffer(vi);
		}
		ret = wait_for_completion_killable(&vi->have_data);
		ret = wait_for_completion_killable(&vi->have_data);
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;
@@ -138,7 +135,6 @@ static void virtio_cleanup(struct hwrng *rng)
{
{
	struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
	struct virtrng_info *vi = (struct virtrng_info *)rng->priv;


	if (vi->busy)
	complete(&vi->have_data);
	complete(&vi->have_data);
}
}


@@ -175,6 +171,9 @@ static int probe_common(struct virtio_device *vdev)
		goto err_find;
		goto err_find;
	}
	}


	/* we always have a pending entropy request */
	request_entropy(vi);

	return 0;
	return 0;


err_find:
err_find:
@@ -193,7 +192,6 @@ static void remove_common(struct virtio_device *vdev)
	vi->data_idx = 0;
	vi->data_idx = 0;
	complete(&vi->have_data);
	complete(&vi->have_data);
	vdev->config->reset(vdev);
	vdev->config->reset(vdev);
	vi->busy = false;
	if (vi->hwrng_register_done)
	if (vi->hwrng_register_done)
		hwrng_unregister(&vi->hwrng);
		hwrng_unregister(&vi->hwrng);
	vdev->config->del_vqs(vdev);
	vdev->config->del_vqs(vdev);