hwrng: virtio - always add a pending request
[ Upstream commit9a4b612d67] 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:ac52578d6e("hwrng: virtio - Fix race on data_avail and actual data") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ffc5ce9c27
commit
e8f51401d6
@@ -20,7 +20,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 */
|
||||||
@@ -44,16 +43,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. */
|
||||||
@@ -69,6 +70,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,13 +101,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;
|
||||||
@@ -126,8 +123,7 @@ 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int probe_common(struct virtio_device *vdev)
|
static int probe_common(struct virtio_device *vdev)
|
||||||
@@ -163,6 +159,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:
|
||||||
@@ -181,7 +180,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);
|
||||||
|
|||||||
Reference in New Issue
Block a user