Re: [PATCH] dm: virtio_rnd: use delayed blocking IO to make virtio_rnd works on Linux based SOS


Yu Wang
 

On 18-08-08 02:41:49, Jie Deng wrote:
Randomness sourced from /dev/random which does not block
once it has been seeded at bootup and you will always get
something when you read from that file. This is true on
Freebsd but unfortunately things are not the same on Linux.
Most cases, you can't read anything from /dev/random especially
on current acrn platform which lacking random events.
virtio_rnd inherted from freebsd doesn't work anymore.

This patch make virtio_rnd works on Linux based SOS. It uses
block IO to sevice the front-end random driver and delays the
read operation into a new thread to avoid blocking the main
notify thread.

Signed-off-by: Jie Deng <jie.deng@...>
---
devicemodel/hw/pci/virtio/virtio_rnd.c | 91 ++++++++++++++++++++--------------
1 file changed, 55 insertions(+), 36 deletions(-)

diff --git a/devicemodel/hw/pci/virtio/virtio_rnd.c b/devicemodel/hw/pci/virtio/virtio_rnd.c
index 618aa66..81f4a8a 100644
--- a/devicemodel/hw/pci/virtio/virtio_rnd.c
+++ b/devicemodel/hw/pci/virtio/virtio_rnd.c
@@ -27,8 +27,6 @@

/*
* virtio entropy device emulation.
- * Randomness is sourced from /dev/random which does not block
- * once it has been seeded at bootup.
*/

#include <fcntl.h>
@@ -57,6 +55,10 @@ struct virtio_rnd {
pthread_mutex_t mtx;
uint64_t cfg;
int fd;
+ int in_progress;
+ pthread_t rx_tid;
+ pthread_mutex_t rx_mtx;
+ pthread_cond_t rx_cond;
/* VBS-K variables */
struct {
enum VBS_K_STATUS status;
@@ -297,37 +299,52 @@ virtio_rnd_reset(void *base)
}
}

-static void
-virtio_rnd_notify(void *base, struct virtio_vq_info *vq)
+static void *
+virtio_rnd_get_entropy(void *param)
{
+ struct virtio_rnd *rnd = param;
+ struct virtio_vq_info *vq = &rnd->vq;
struct iovec iov;
- struct virtio_rnd *rnd;
- int len;
uint16_t idx;
+ int len, error;

- rnd = base;
-
- if (rnd->fd < 0) {
- vq_endchains(vq, 0);
- return;
- }
+ for (;;) {
+ pthread_mutex_lock(&rnd->rx_mtx);
+ rnd->in_progress = 0;
Is the in_process is necessary? We call pthread_cond_signal when thread
already awake, what is the impact? I see net does the same logic, but
heci not. Let's keep it first.

@Shuo, please help evaluate HECI in future.

Others looks good to me.

Acked-by: Yu Wang <yu1.wang@...>


+ error = pthread_cond_wait(&rnd->rx_cond, &rnd->rx_mtx);
+ assert(error == 0);

- while (vq_has_descs(vq)) {
- vq_getchain(vq, &idx, &iov, 1, NULL);
+ rnd->in_progress = 1;
+ pthread_mutex_unlock(&rnd->rx_mtx);

- len = read(rnd->fd, iov.iov_base, iov.iov_len);
+ while(vq_has_descs(vq)) {
+ vq_getchain(vq, &idx, &iov, 1, NULL);

- DPRINTF(("%s: %d\r\n", __func__, len));
+ len = read(rnd->fd, iov.iov_base, iov.iov_len);
+ assert(len > 0);

- /* Catastrophe if unable to read from /dev/random */
- assert(len > 0);
+ /* release this chain and handle more */
+ vq_relchain(vq, idx, len);
+ }

- /*
- * Release this chain and handle more
- */
- vq_relchain(vq, idx, len);
+ vq_endchains(vq, 1);
}
- vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
+}
+
+static void
+virtio_rnd_notify(void *base, struct virtio_vq_info *vq)
+{
+ struct virtio_rnd *rnd = base;
+
+ /* Any ring entries to process */
+ if (!vq_has_descs(vq))
+ return;
+
+ /* Signal the tx thread for processing */
+ pthread_mutex_lock(&rnd->rx_mtx);
+ if (rnd->in_progress == 0)
+ pthread_cond_signal(&rnd->rx_cond);
+ pthread_mutex_unlock(&rnd->rx_mtx);
}

static int
@@ -335,13 +352,12 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
struct virtio_rnd *rnd = NULL;
int fd;
- int len;
- uint8_t v;
pthread_mutexattr_t attr;
int rc;
char *opt;
char *vbs_k_opt = NULL;
enum VBS_K_STATUS kstat = VIRTIO_DEV_INITIAL;
+ char tname[MAXCOMLEN + 1];

while ((opt = strsep(&opts, ",")) != NULL) {
/* vbs_k_opt should be kernel=on */
@@ -357,19 +373,9 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
/*
* Should always be able to open /dev/random.
*/
- fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
-
+ fd = open("/dev/random", O_RDONLY);
assert(fd >= 0);

- /*
- * Check that device is seeded and non-blocking.
- */
- len = read(fd, &v, sizeof(v));
- if (len <= 0) {
- WPRINTF(("virtio_rnd: /dev/random not ready, read(): %d", len));
- goto fail;
- }
-
rnd = calloc(1, sizeof(struct virtio_rnd));
if (!rnd) {
WPRINTF(("virtio_rnd: calloc returns NULL\n"));
@@ -436,6 +442,15 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)

virtio_set_io_bar(&rnd->base, 0);

+ rnd->in_progress = 0;
+ pthread_mutex_init(&rnd->rx_mtx, NULL);
+ pthread_cond_init(&rnd->rx_cond, NULL);
+ pthread_create(&rnd->rx_tid, NULL, virtio_rnd_get_entropy,
+ (void *)rnd);
+ snprintf(tname, sizeof(tname), "vtrnd-%d:%d tx", dev->slot,
+ dev->func);
+ pthread_setname_np(rnd->rx_tid, tname);
+
return 0;

fail:
@@ -454,6 +469,7 @@ static void
virtio_rnd_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
struct virtio_rnd *rnd;
+ void *jval;

rnd = dev->arg;
if (rnd == NULL) {
@@ -461,6 +477,9 @@ virtio_rnd_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
return;
}

+ pthread_cancel(rnd->rx_tid);
+ pthread_join(rnd->rx_tid, &jval);
+
if (rnd->vbs_k.status == VIRTIO_DEV_STARTED) {
DPRINTF(("%s: deinit virtio_rnd_k!\n", __func__));
virtio_rnd_kernel_stop(rnd);
--
2.7.4

Join acrn-dev@lists.projectacrn.org to automatically receive all group messages.