Skip to content

Commit 8348800

Browse files
ssqrelijinxia
authored andcommitted
dm: virtio_rnd: use delayed blocking IO to make virtio_rnd works on Linux based SOS
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 makes virtio_rnd working on Linux based SOS. It uses blocking 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@intel.com> Reviewed-by: Shuo Liu <shuo.a.liu@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
1 parent 98aa74b commit 8348800

File tree

1 file changed

+55
-36
lines changed

1 file changed

+55
-36
lines changed

devicemodel/hw/pci/virtio/virtio_rnd.c

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727

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

3432
#include <fcntl.h>
@@ -57,6 +55,10 @@ struct virtio_rnd {
5755
pthread_mutex_t mtx;
5856
uint64_t cfg;
5957
int fd;
58+
int in_progress;
59+
pthread_t rx_tid;
60+
pthread_mutex_t rx_mtx;
61+
pthread_cond_t rx_cond;
6062
/* VBS-K variables */
6163
struct {
6264
enum VBS_K_STATUS status;
@@ -295,51 +297,65 @@ virtio_rnd_reset(void *base)
295297
}
296298
}
297299

298-
static void
299-
virtio_rnd_notify(void *base, struct virtio_vq_info *vq)
300+
static void *
301+
virtio_rnd_get_entropy(void *param)
300302
{
303+
struct virtio_rnd *rnd = param;
304+
struct virtio_vq_info *vq = &rnd->vq;
301305
struct iovec iov;
302-
struct virtio_rnd *rnd;
303-
int len;
304306
uint16_t idx;
307+
int len, error;
305308

306-
rnd = base;
307-
308-
if (rnd->fd < 0) {
309-
vq_endchains(vq, 0);
310-
return;
311-
}
309+
for (;;) {
310+
pthread_mutex_lock(&rnd->rx_mtx);
311+
rnd->in_progress = 0;
312+
error = pthread_cond_wait(&rnd->rx_cond, &rnd->rx_mtx);
313+
assert(error == 0);
312314

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

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

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

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

323-
/*
324-
* Release this chain and handle more
325-
*/
326-
vq_relchain(vq, idx, len);
328+
vq_endchains(vq, 1);
327329
}
328-
vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
330+
}
331+
332+
static void
333+
virtio_rnd_notify(void *base, struct virtio_vq_info *vq)
334+
{
335+
struct virtio_rnd *rnd = base;
336+
337+
/* Any ring entries to process */
338+
if (!vq_has_descs(vq))
339+
return;
340+
341+
/* Signal the thread for processing */
342+
pthread_mutex_lock(&rnd->rx_mtx);
343+
if (rnd->in_progress == 0)
344+
pthread_cond_signal(&rnd->rx_cond);
345+
pthread_mutex_unlock(&rnd->rx_mtx);
329346
}
330347

331348
static int
332349
virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
333350
{
334351
struct virtio_rnd *rnd = NULL;
335352
int fd;
336-
int len;
337-
uint8_t v;
338353
pthread_mutexattr_t attr;
339354
int rc;
340355
char *opt;
341356
char *vbs_k_opt = NULL;
342357
enum VBS_K_STATUS kstat = VIRTIO_DEV_INITIAL;
358+
char tname[MAXCOMLEN + 1];
343359

344360
while ((opt = strsep(&opts, ",")) != NULL) {
345361
/* vbs_k_opt should be kernel=on */
@@ -355,19 +371,9 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
355371
/*
356372
* Should always be able to open /dev/random.
357373
*/
358-
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
359-
374+
fd = open("/dev/random", O_RDONLY);
360375
assert(fd >= 0);
361376

362-
/*
363-
* Check that device is seeded and non-blocking.
364-
*/
365-
len = read(fd, &v, sizeof(v));
366-
if (len <= 0) {
367-
WPRINTF(("virtio_rnd: /dev/random not ready, read(): %d", len));
368-
goto fail;
369-
}
370-
371377
rnd = calloc(1, sizeof(struct virtio_rnd));
372378
if (!rnd) {
373379
WPRINTF(("virtio_rnd: calloc returns NULL\n"));
@@ -434,6 +440,15 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
434440

435441
virtio_set_io_bar(&rnd->base, 0);
436442

443+
rnd->in_progress = 0;
444+
pthread_mutex_init(&rnd->rx_mtx, NULL);
445+
pthread_cond_init(&rnd->rx_cond, NULL);
446+
pthread_create(&rnd->rx_tid, NULL, virtio_rnd_get_entropy,
447+
(void *)rnd);
448+
snprintf(tname, sizeof(tname), "vtrnd-%d:%d tx", dev->slot,
449+
dev->func);
450+
pthread_setname_np(rnd->rx_tid, tname);
451+
437452
return 0;
438453

439454
fail:
@@ -452,13 +467,17 @@ static void
452467
virtio_rnd_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
453468
{
454469
struct virtio_rnd *rnd;
470+
void *jval;
455471

456472
rnd = dev->arg;
457473
if (rnd == NULL) {
458474
DPRINTF(("%s: rnd is NULL\n", __func__));
459475
return;
460476
}
461477

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

0 commit comments

Comments
 (0)