27
27
28
28
/*
29
29
* virtio entropy device emulation.
30
- * Randomness is sourced from /dev/random which does not block
31
- * once it has been seeded at bootup.
32
30
*/
33
31
34
32
#include <fcntl.h>
@@ -57,6 +55,10 @@ struct virtio_rnd {
57
55
pthread_mutex_t mtx ;
58
56
uint64_t cfg ;
59
57
int fd ;
58
+ int in_progress ;
59
+ pthread_t rx_tid ;
60
+ pthread_mutex_t rx_mtx ;
61
+ pthread_cond_t rx_cond ;
60
62
/* VBS-K variables */
61
63
struct {
62
64
enum VBS_K_STATUS status ;
@@ -295,51 +297,65 @@ virtio_rnd_reset(void *base)
295
297
}
296
298
}
297
299
298
- static void
299
- virtio_rnd_notify (void * base , struct virtio_vq_info * vq )
300
+ static void *
301
+ virtio_rnd_get_entropy (void * param )
300
302
{
303
+ struct virtio_rnd * rnd = param ;
304
+ struct virtio_vq_info * vq = & rnd -> vq ;
301
305
struct iovec iov ;
302
- struct virtio_rnd * rnd ;
303
- int len ;
304
306
uint16_t idx ;
307
+ int len , error ;
305
308
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 );
312
314
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 );
315
317
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 );
317
320
318
- DPRINTF (("%s: %d\r\n" , __func__ , len ));
321
+ len = read (rnd -> fd , iov .iov_base , iov .iov_len );
322
+ assert (len > 0 );
319
323
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
+ }
322
327
323
- /*
324
- * Release this chain and handle more
325
- */
326
- vq_relchain (vq , idx , len );
328
+ vq_endchains (vq , 1 );
327
329
}
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 );
329
346
}
330
347
331
348
static int
332
349
virtio_rnd_init (struct vmctx * ctx , struct pci_vdev * dev , char * opts )
333
350
{
334
351
struct virtio_rnd * rnd = NULL ;
335
352
int fd ;
336
- int len ;
337
- uint8_t v ;
338
353
pthread_mutexattr_t attr ;
339
354
int rc ;
340
355
char * opt ;
341
356
char * vbs_k_opt = NULL ;
342
357
enum VBS_K_STATUS kstat = VIRTIO_DEV_INITIAL ;
358
+ char tname [MAXCOMLEN + 1 ];
343
359
344
360
while ((opt = strsep (& opts , "," )) != NULL ) {
345
361
/* vbs_k_opt should be kernel=on */
@@ -355,19 +371,9 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
355
371
/*
356
372
* Should always be able to open /dev/random.
357
373
*/
358
- fd = open ("/dev/random" , O_RDONLY | O_NONBLOCK );
359
-
374
+ fd = open ("/dev/random" , O_RDONLY );
360
375
assert (fd >= 0 );
361
376
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
-
371
377
rnd = calloc (1 , sizeof (struct virtio_rnd ));
372
378
if (!rnd ) {
373
379
WPRINTF (("virtio_rnd: calloc returns NULL\n" ));
@@ -434,6 +440,15 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
434
440
435
441
virtio_set_io_bar (& rnd -> base , 0 );
436
442
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
+
437
452
return 0 ;
438
453
439
454
fail :
@@ -452,13 +467,17 @@ static void
452
467
virtio_rnd_deinit (struct vmctx * ctx , struct pci_vdev * dev , char * opts )
453
468
{
454
469
struct virtio_rnd * rnd ;
470
+ void * jval ;
455
471
456
472
rnd = dev -> arg ;
457
473
if (rnd == NULL ) {
458
474
DPRINTF (("%s: rnd is NULL\n" , __func__ ));
459
475
return ;
460
476
}
461
477
478
+ pthread_cancel (rnd -> rx_tid );
479
+ pthread_join (rnd -> rx_tid , & jval );
480
+
462
481
if (rnd -> vbs_k .status == VIRTIO_DEV_STARTED ) {
463
482
DPRINTF (("%s: deinit virtio_rnd_k!\n" , __func__ ));
464
483
virtio_rnd_kernel_stop (rnd );
0 commit comments