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

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

hwrng: virtio - don't waste entropy



[ Upstream commit 5c8e933050044d6dd2a000f9a5756ae73cbe7c44 ]

if we don't use all the entropy available in the buffer, keep it
and use it later.

Signed-off-by: default avatarLaurent Vivier <lvivier@redhat.com>
Link: https://lore.kernel.org/r/20211028101111.128049-4-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 eaf91a80
Loading
Loading
Loading
Loading
+35 −17
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ struct virtrng_info {
	/* data transfer */
	struct completion have_data;
	unsigned int data_avail;
	unsigned int data_idx;
	/* minimal size returned by rng_buffer_size() */
#if SMP_CACHE_BYTES < 32
	u8 data[32];
@@ -54,6 +55,9 @@ static void random_recv_done(struct virtqueue *vq)
	if (!virtqueue_get_buf(vi->vq, &vi->data_avail))
		return;

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

	complete(&vi->have_data);
}

@@ -70,6 +74,16 @@ static void register_buffer(struct virtrng_info *vi)
	virtqueue_kick(vi->vq);
}

static unsigned int copy_data(struct virtrng_info *vi, void *buf,
			      unsigned int size)
{
	size = min_t(unsigned int, size, vi->data_avail);
	memcpy(buf, vi->data + vi->data_idx, size);
	vi->data_idx += size;
	vi->data_avail -= size;
	return size;
}

static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
{
	int ret;
@@ -80,17 +94,29 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
	if (vi->hwrng_removed)
		return -ENODEV;

	if (!vi->busy) {
		vi->busy = true;
		reinit_completion(&vi->have_data);
		register_buffer(vi);
	read = 0;

	/* copy available data */
	if (vi->data_avail) {
		chunk = copy_data(vi, buf, size);
		size -= chunk;
		read += chunk;
	}

	if (!wait)
		return 0;
		return read;

	read = 0;
	/* We have already copied available entropy,
	 * 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);
		}
		ret = wait_for_completion_killable(&vi->have_data);
		if (ret < 0)
			return ret;
@@ -100,20 +126,11 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
		if (vi->data_avail == 0)
			return read;

		chunk = min_t(unsigned int, size, vi->data_avail);
		memcpy(buf + read, vi->data, chunk);
		read += chunk;
		chunk = copy_data(vi, buf + read, size);
		size -= chunk;
		vi->data_avail = 0;

		if (size != 0) {
			reinit_completion(&vi->have_data);
			register_buffer(vi);
		}
		read += chunk;
	}

	vi->busy = false;

	return read;
}

@@ -173,6 +190,7 @@ static void remove_common(struct virtio_device *vdev)

	vi->hwrng_removed = true;
	vi->data_avail = 0;
	vi->data_idx = 0;
	complete(&vi->have_data);
	vdev->config->reset(vdev);
	vi->busy = false;