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

Commit b70315e4 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 102a354d
Loading
Loading
Loading
Loading
+12 −14
Original line number Diff line number Diff line
@@ -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,7 +122,6 @@ static void virtio_cleanup(struct hwrng *rng)
{
	struct virtrng_info *vi = (struct virtrng_info *)rng->priv;

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

@@ -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);