@@ -94,11 +94,13 @@ static void virtio_blk_update_status(virtio_blk_state_t *vblk, uint32_t status)
9494 return ;
9595
9696 /* Reset */
97+ uint32_t device_features = vblk -> device_features ;
9798 uint32_t * ram = vblk -> ram ;
9899 uint32_t * disk = vblk -> disk ;
99100 void * priv = vblk -> priv ;
100101 uint32_t capacity = VBLK_PRIV (vblk )-> capacity ;
101102 memset (vblk , 0 , sizeof (* vblk ));
103+ vblk -> device_features = device_features ;
102104 vblk -> ram = ram ;
103105 vblk -> disk = disk ;
104106 vblk -> priv = priv ;
@@ -187,6 +189,11 @@ static int virtio_blk_desc_handler(virtio_blk_state_t *vblk,
187189 virtio_blk_read_handler (vblk , sector , vq_desc [1 ].addr , vq_desc [1 ].len );
188190 break ;
189191 case VIRTIO_BLK_T_OUT :
192+ if (vblk -> device_features & VIRTIO_BLK_F_RO ) { /* readonly */
193+ rv_log_error ("Fail to write on a read only block device" );
194+ * status = VIRTIO_BLK_S_IOERR ;
195+ return -1 ;
196+ }
190197 virtio_blk_write_handler (vblk , sector , vq_desc [1 ].addr , vq_desc [1 ].len );
191198 break ;
192199 default :
@@ -279,9 +286,9 @@ uint32_t virtio_blk_read(virtio_blk_state_t *vblk, uint32_t addr)
279286 case _ (VendorID ):
280287 return VIRTIO_VENDOR_ID ;
281288 case _ (DeviceFeatures ):
282- return vblk -> driver_features_sel == 0
283- ? VBLK_FEATURES_0
284- : (vblk -> driver_features_sel == 1 ? VBLK_FEATURES_1 : 0 );
289+ return vblk -> device_features_sel == 0
290+ ? VBLK_FEATURES_0 | vblk -> device_features
291+ : (vblk -> device_features_sel == 1 ? VBLK_FEATURES_1 : 0 );
285292 case _ (QueueNumMax ):
286293 return VBLK_QUEUE_NUM_MAX ;
287294 case _ (QueueReady ):
@@ -305,7 +312,7 @@ void virtio_blk_write(virtio_blk_state_t *vblk, uint32_t addr, uint32_t value)
305312#define _ (reg ) VIRTIO_##reg
306313 switch (addr ) {
307314 case _ (DeviceFeaturesSel ):
308- vblk -> driver_features_sel = value ;
315+ vblk -> device_features_sel = value ;
309316 break ;
310317 case _ (DriverFeatures ):
311318 vblk -> driver_features_sel == 0 ? (vblk -> driver_features = value ) : 0 ;
@@ -371,7 +378,9 @@ void virtio_blk_write(virtio_blk_state_t *vblk, uint32_t addr, uint32_t value)
371378#undef _
372379}
373380
374- uint32_t * virtio_blk_init (virtio_blk_state_t * vblk , char * disk_file )
381+ uint32_t * virtio_blk_init (virtio_blk_state_t * vblk ,
382+ char * disk_file ,
383+ bool readonly )
375384{
376385 if (vblk_dev_cnt >= VBLK_DEV_CNT_MAX ) {
377386 rv_log_error (
@@ -391,7 +400,7 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
391400 }
392401
393402 /* Open disk file */
394- int disk_fd = open (disk_file , O_RDWR );
403+ int disk_fd = open (disk_file , readonly ? O_RDONLY : O_RDWR );
395404 if (disk_fd < 0 ) {
396405 rv_log_error ("Could not open %s" , disk_file );
397406 exit (EXIT_FAILURE );
@@ -405,8 +414,9 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
405414 /* Set up the disk memory */
406415 uint32_t * disk_mem ;
407416#if HAVE_MMAP
408- disk_mem = mmap (NULL , VBLK_PRIV (vblk )-> disk_size , PROT_READ | PROT_WRITE ,
409- MAP_SHARED , disk_fd , 0 );
417+ disk_mem = mmap (NULL , VBLK_PRIV (vblk )-> disk_size ,
418+ readonly ? PROT_READ : (PROT_READ | PROT_WRITE ), MAP_SHARED ,
419+ disk_fd , 0 );
410420 if (disk_mem == MAP_FAILED )
411421 goto err ;
412422#else
@@ -421,6 +431,9 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
421431 VBLK_PRIV (vblk )-> capacity =
422432 (VBLK_PRIV (vblk )-> disk_size - 1 ) / DISK_BLK_SIZE + 1 ;
423433
434+ if (readonly )
435+ vblk -> device_features = VIRTIO_BLK_F_RO ;
436+
424437 return disk_mem ;
425438
426439err :
0 commit comments