@@ -18,6 +18,7 @@ use super::{DescriptorChain, Queue, VirtioDevice, INTERRUPT_STATUS_USED_RING, TY
1818use sys_util:: Result as SysResult ;
1919use sys_util:: { EventFd , GuestAddress , GuestMemory , GuestMemoryError } ;
2020use virtio_sys:: virtio_blk:: * ;
21+ use virtio_sys:: virtio_config:: * ;
2122
2223const SECTOR_SHIFT : u8 = 9 ;
2324const SECTOR_SIZE : u64 = 0x01 << SECTOR_SHIFT ;
@@ -313,6 +314,8 @@ impl EpollConfig {
313314pub struct Block {
314315 kill_evt : Option < EventFd > ,
315316 disk_image : Option < File > ,
317+ avail_features : u64 ,
318+ acked_features : u64 ,
316319 config_space : Vec < u8 > ,
317320 epoll_config : EpollConfig ,
318321}
@@ -333,7 +336,11 @@ impl Block {
333336 /// Create a new virtio block device that operates on the given file.
334337 ///
335338 /// The given file must be seekable and sizable.
336- pub fn new ( mut disk_image : File , epoll_config : EpollConfig ) -> SysResult < Block > {
339+ pub fn new (
340+ mut disk_image : File ,
341+ is_disk_read_only : bool ,
342+ epoll_config : EpollConfig ,
343+ ) -> SysResult < Block > {
337344 let disk_size = disk_image. seek ( SeekFrom :: End ( 0 ) ) ? as u64 ;
338345 if disk_size % SECTOR_SIZE != 0 {
339346 warn ! (
@@ -342,9 +349,18 @@ impl Block {
342349 disk_size, SECTOR_SIZE
343350 ) ;
344351 }
352+
353+ let mut avail_features = 1 << VIRTIO_F_VERSION_1 ;
354+
355+ if is_disk_read_only {
356+ avail_features |= 1 << VIRTIO_BLK_F_RO ;
357+ } ;
358+
345359 Ok ( Block {
346360 kill_evt : None ,
347361 disk_image : Some ( disk_image) ,
362+ avail_features,
363+ acked_features : 0u64 ,
348364 config_space : build_config_space ( disk_size) ,
349365 epoll_config,
350366 } )
@@ -369,6 +385,46 @@ impl VirtioDevice for Block {
369385 QUEUE_SIZES
370386 }
371387
388+ fn features ( & self , page : u32 ) -> u32 {
389+ match page {
390+ // Get the lower 32-bits of the features bitfield.
391+ 0 => self . avail_features as u32 ,
392+ // Get the upper 32-bits of the features bitfield.
393+ 1 => ( self . avail_features >> 32 ) as u32 ,
394+ _ => {
395+ warn ! (
396+ "block: virtio-block got request for features page: {}" ,
397+ page
398+ ) ;
399+ 0u32
400+ }
401+ }
402+ }
403+
404+ fn ack_features ( & mut self , page : u32 , value : u32 ) {
405+ let mut v = match page {
406+ 0 => value as u64 ,
407+ 1 => ( value as u64 ) << 32 ,
408+ _ => {
409+ warn ! (
410+ "block: virtio-block device cannot ack unknown feature page: {}" ,
411+ page
412+ ) ;
413+ 0u64
414+ }
415+ } ;
416+
417+ // Check if the guest is ACK'ing a feature that we didn't claim to have.
418+ let unrequested_features = v & !self . avail_features ;
419+ if unrequested_features != 0 {
420+ warn ! ( "block: virtio-block got unknown feature ack: {:x}" , v) ;
421+
422+ // Don't count these features as acked.
423+ v &= !unrequested_features;
424+ }
425+ self . acked_features |= v;
426+ }
427+
372428 fn read_config ( & self , offset : u64 , mut data : & mut [ u8 ] ) {
373429 let config_len = self . config_space . len ( ) as u64 ;
374430 if offset >= config_len {
@@ -504,7 +560,7 @@ mod tests {
504560 f. set_len ( 0x1000 ) . unwrap ( ) ;
505561
506562 DummyBlock {
507- block : Block :: new ( f, epoll_config) . unwrap ( ) ,
563+ block : Block :: new ( f, false , epoll_config) . unwrap ( ) ,
508564 epoll_raw_fd,
509565 _receiver,
510566 }
0 commit comments