4
4
*/
5
5
6
6
#include <assert.h>
7
+ #include <errno.h>
7
8
#include <fcntl.h>
9
+ #include <libgen.h>
8
10
#include <stdbool.h>
9
11
#include <stdio.h>
10
12
#include <stdlib.h>
11
13
#include <string.h>
14
+ #include <sys/ioctl.h>
12
15
#include <sys/mman.h>
13
16
#include <sys/stat.h>
14
17
#include <unistd.h>
15
18
19
+ /*
20
+ * The /dev/ block devices cannot be embedded to the part of the wasm.
21
+ * Thus, accessing /dev/ block devices is not supported for wasm.
22
+ */
23
+ #if !defined(__EMSCRIPTEN__ )
24
+ #if defined(__APPLE__ )
25
+ #include <sys/disk.h> /* DKIOCGETBLOCKCOUNT and DKIOCGETBLOCKSIZE */
26
+ #else
27
+ #include <linux/fs.h> /* BLKGETSIZE64 */
28
+ #endif
29
+ #endif /* !defined(__EMSCRIPTEN__) */
30
+
16
31
#include "virtio.h"
17
32
18
33
#define DISK_BLK_SIZE 512
@@ -97,12 +112,16 @@ static void virtio_blk_update_status(virtio_blk_state_t *vblk, uint32_t status)
97
112
uint32_t device_features = vblk -> device_features ;
98
113
uint32_t * ram = vblk -> ram ;
99
114
uint32_t * disk = vblk -> disk ;
115
+ uint64_t disk_size = vblk -> disk_size ;
116
+ int disk_fd = vblk -> disk_fd ;
100
117
void * priv = vblk -> priv ;
101
118
uint32_t capacity = VBLK_PRIV (vblk )-> capacity ;
102
119
memset (vblk , 0 , sizeof (* vblk ));
103
120
vblk -> device_features = device_features ;
104
121
vblk -> ram = ram ;
105
122
vblk -> disk = disk ;
123
+ vblk -> disk_size = disk_size ;
124
+ vblk -> disk_fd = disk_fd ;
106
125
vblk -> priv = priv ;
107
126
VBLK_PRIV (vblk )-> capacity = capacity ;
108
127
}
@@ -388,6 +407,12 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk,
388
407
exit (EXIT_FAILURE );
389
408
}
390
409
410
+ /*
411
+ * For mmap_fallback, if vblk is not specified, disk_fd should remain -1 and
412
+ * no fsync should be performed on exit.
413
+ */
414
+ vblk -> disk_fd = -1 ;
415
+
391
416
/* Allocate memory for the private member */
392
417
vblk -> priv = & vblk_configs [vblk_dev_cnt ++ ];
393
418
@@ -402,30 +427,93 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk,
402
427
/* Open disk file */
403
428
int disk_fd = open (disk_file , readonly ? O_RDONLY : O_RDWR );
404
429
if (disk_fd < 0 ) {
405
- rv_log_error ("Could not open %s" , disk_file );
406
- exit ( EXIT_FAILURE ) ;
430
+ rv_log_error ("Could not open %s: %s " , disk_file , strerror ( errno ) );
431
+ goto fail ;
407
432
}
408
433
409
- /* Get the disk image size */
410
434
struct stat st ;
411
- fstat (disk_fd , & st );
412
- VBLK_PRIV (vblk )-> disk_size = st .st_size ;
435
+ if (fstat (disk_fd , & st ) == -1 ) {
436
+ rv_log_error ("fstat failed: %s" , strerror (errno ));
437
+ goto disk_size_fail ;
438
+ }
439
+
440
+ const char * disk_file_dirname = dirname (disk_file );
441
+ if (!disk_file_dirname ) {
442
+ rv_log_error ("Fail dirname disk_file: %s: %s" , disk_file ,
443
+ strerror (errno ));
444
+ goto disk_size_fail ;
445
+ }
446
+ /* Get the disk size */
447
+ uint64_t disk_size ;
448
+ if (!strcmp (disk_file_dirname , "/dev" )) { /* from /dev/, leverage ioctl */
449
+ #if !defined(__EMSCRIPTEN__ )
450
+ #if defined(__APPLE__ )
451
+ uint32_t block_size ;
452
+ uint64_t block_count ;
453
+ if (ioctl (disk_fd , DKIOCGETBLOCKCOUNT , & block_count ) == -1 ) {
454
+ rv_log_error ("DKIOCGETBLOCKCOUNT failed: %s" , strerror (errno ));
455
+ goto disk_size_fail ;
456
+ }
457
+ if (ioctl (disk_fd , DKIOCGETBLOCKSIZE , & block_size ) == -1 ) {
458
+ rv_log_error ("DKIOCGETBLOCKSIZE failed: %s" , strerror (errno ));
459
+ goto disk_size_fail ;
460
+ }
461
+ disk_size = block_count * block_size ;
462
+ #else /* Linux */
463
+ if (ioctl (disk_fd , BLKGETSIZE64 , & disk_size ) == -1 ) {
464
+ rv_log_error ("BLKGETSIZE64 failed: %s" , strerror (errno ));
465
+ goto disk_size_fail ;
466
+ }
467
+ #endif
468
+ #endif /* !defined(__EMSCRIPTEN__) */
469
+ } else { /* other path, stat it as normal file */
470
+ struct stat st ;
471
+ if (fstat (disk_fd , & st ) == -1 ) {
472
+ rv_log_error ("fstat failed" );
473
+ goto disk_size_fail ;
474
+ }
475
+ disk_size = st .st_size ;
476
+ }
477
+ VBLK_PRIV (vblk )-> disk_size = disk_size ;
413
478
414
479
/* Set up the disk memory */
415
480
uint32_t * disk_mem ;
416
481
#if HAVE_MMAP
417
482
disk_mem = mmap (NULL , VBLK_PRIV (vblk )-> disk_size ,
418
483
readonly ? PROT_READ : (PROT_READ | PROT_WRITE ), MAP_SHARED ,
419
484
disk_fd , 0 );
420
- if (disk_mem == MAP_FAILED )
421
- goto err ;
422
- #else
485
+ if (disk_mem == MAP_FAILED ) {
486
+ if (errno != EINVAL )
487
+ goto disk_mem_err ;
488
+ /*
489
+ * On Apple platforms, mmap() on block devices appears to be unsupported
490
+ * and EINVAL is set to errno.
491
+ */
492
+ rv_log_trace (
493
+ "Fallback to malloc-based block device due to mmap() failure" );
494
+ goto mmap_fallback ;
495
+ }
496
+ /*
497
+ * disk_fd should be closed on exit after flushing heap data back to the
498
+ * device when using mmap_fallback.
499
+ */
500
+ close (disk_fd );
501
+ goto disk_mem_ok ;
502
+ #endif
503
+
504
+ mmap_fallback :
423
505
disk_mem = malloc (VBLK_PRIV (vblk )-> disk_size );
424
506
if (!disk_mem )
425
- goto err ;
426
- #endif
507
+ goto disk_mem_err ;
508
+ vblk -> disk_fd = disk_fd ;
509
+ vblk -> disk_size = disk_size ;
510
+ if (pread (disk_fd , disk_mem , disk_size , 0 ) == -1 ) {
511
+ rv_log_error ("pread block device failed: %s" , strerror (errno ));
512
+ goto disk_mem_err ;
513
+ }
514
+
515
+ disk_mem_ok :
427
516
assert (!(((uintptr_t ) disk_mem ) & 0b11 ));
428
- close (disk_fd );
429
517
430
518
vblk -> disk = disk_mem ;
431
519
VBLK_PRIV (vblk )-> capacity =
@@ -436,9 +524,14 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk,
436
524
437
525
return disk_mem ;
438
526
439
- err :
440
- rv_log_error ("Could not map disk %s" , disk_file );
441
- return NULL ;
527
+ disk_mem_err :
528
+ rv_log_error ("Could not map disk %s: %s" , disk_file , strerror (errno ));
529
+
530
+ disk_size_fail :
531
+ close (disk_fd );
532
+
533
+ fail :
534
+ exit (EXIT_FAILURE );
442
535
}
443
536
444
537
virtio_blk_state_t * vblk_new ()
@@ -450,10 +543,12 @@ virtio_blk_state_t *vblk_new()
450
543
451
544
void vblk_delete (virtio_blk_state_t * vblk )
452
545
{
546
+ /* mmap_fallback is used */
547
+ if (vblk -> disk_fd != -1 )
548
+ free (vblk -> disk );
453
549
#if HAVE_MMAP
454
- munmap (vblk -> disk , VBLK_PRIV (vblk )-> disk_size );
455
- #else
456
- free (vblk -> disk );
550
+ else
551
+ munmap (vblk -> disk , VBLK_PRIV (vblk )-> disk_size );
457
552
#endif
458
553
free (vblk );
459
554
}
0 commit comments