@@ -19,7 +19,7 @@ use logger::{error, warn, Metric, METRICS};
1919use rate_limiter:: { RateLimiter , TokenType } ;
2020use utils:: eventfd:: EventFd ;
2121use virtio_gen:: virtio_blk:: * ;
22- use vm_memory:: { Bytes , GuestMemoryMmap } ;
22+ use vm_memory:: { Bytes , GuestMemoryError , GuestMemoryMmap } ;
2323
2424use super :: {
2525 super :: { ActivateResult , DeviceState , Queue , VirtioDevice , TYPE_BLOCK , VIRTIO_MMIO_INT_VRING } ,
@@ -257,15 +257,46 @@ impl Block {
257257 break ;
258258 }
259259 }
260+
260261 let status = match request. execute ( & mut self . disk , mem) {
261262 Ok ( l) => {
262- len = l;
263- VIRTIO_BLK_S_OK
263+ // Account for the status byte as well.
264+ // With a non-faulty driver, we shouldn't get to the point where we
265+ // overflow here (since data len must be a multiple of 512 bytes, so
266+ // it can't be u32::MAX). In the future, this should be fixed at the
267+ // request parsing level, so no data will actually be transferred in
268+ // scenarios like this one.
269+ if let Some ( l) = l. checked_add ( 1 ) {
270+ len = l;
271+ VIRTIO_BLK_S_OK
272+ } else {
273+ len = l;
274+ VIRTIO_BLK_S_IOERR
275+ }
264276 }
265277 Err ( e) => {
266- error ! ( "Failed to execute request: {:?}" , e) ;
267278 METRICS . block . invalid_reqs_count . inc ( ) ;
268- len = 1 ; // We need at least 1 byte for the status.
279+ match e {
280+ ExecuteError :: Read ( GuestMemoryError :: PartialBuffer {
281+ completed,
282+ expected,
283+ } ) => {
284+ error ! (
285+ "Failed to execute virtio block read request: can only \
286+ write {} of {} bytes.",
287+ completed, expected
288+ ) ;
289+ METRICS . block . read_bytes . add ( completed) ;
290+ // This can not overflow since `completed` < data len which is
291+ // an u32.
292+ len = completed as u32 + 1 ;
293+ }
294+ _ => {
295+ error ! ( "Failed to execute virtio block request: {:?}" , e) ;
296+ // Status byte only.
297+ len = 1 ;
298+ }
299+ } ;
269300 e. status ( )
270301 }
271302 } ;
@@ -766,7 +797,7 @@ pub(crate) mod tests {
766797
767798 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
768799 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
769- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
800+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
770801 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
771802 }
772803
@@ -789,10 +820,100 @@ pub(crate) mod tests {
789820
790821 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
791822 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
792- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, vq. dtable[ 1 ] . len. get( ) ) ;
823+ // Added status byte length.
824+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, vq. dtable[ 1 ] . len. get( ) + 1 ) ;
793825 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
826+ }
827+
828+ // Read with error.
829+ {
830+ vq. used . idx . set ( 0 ) ;
831+ block. set_queue ( 0 , vq. create_queue ( ) ) ;
832+
833+ mem. write_obj :: < u32 > ( VIRTIO_BLK_T_IN , request_type_addr)
834+ . unwrap ( ) ;
835+ vq. dtable [ 1 ]
836+ . flags
837+ . set ( VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE ) ;
838+
839+ let size = block. disk . file . seek ( SeekFrom :: End ( 0 ) ) . unwrap ( ) ;
840+ block. disk . file . set_len ( size / 2 ) . unwrap ( ) ;
841+ mem. write_obj ( 10 , GuestAddress ( request_type_addr. 0 + 8 ) )
842+ . unwrap ( ) ;
843+
844+ invoke_handler_for_queue_event ( & mut block) ;
845+
846+ assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
847+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
848+
849+ // Only status byte length.
850+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
851+ assert_eq ! (
852+ mem. read_obj:: <u32 >( status_addr) . unwrap( ) ,
853+ VIRTIO_BLK_S_IOERR
854+ ) ;
855+ assert_eq ! ( mem. read_obj:: <u64 >( data_addr) . unwrap( ) , 123_456_789 ) ;
856+ }
857+
858+ // Partial buffer error on read.
859+ {
860+ vq. used . idx . set ( 0 ) ;
861+ block. set_queue ( 0 , vq. create_queue ( ) ) ;
862+
863+ mem. write_obj :: < u32 > ( VIRTIO_BLK_T_IN , request_type_addr)
864+ . unwrap ( ) ;
865+ vq. dtable [ 1 ]
866+ . flags
867+ . set ( VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE ) ;
868+
869+ let size = block. disk . file . seek ( SeekFrom :: End ( 0 ) ) . unwrap ( ) ;
870+ block. disk . file . set_len ( size / 2 ) . unwrap ( ) ;
871+ // Update sector number: stored at `request_type_addr.0 + 8`
872+ mem. write_obj ( 5 , GuestAddress ( request_type_addr. 0 + 8 ) )
873+ . unwrap ( ) ;
874+
875+ // This will attempt to read past end of file.
876+ invoke_handler_for_queue_event ( & mut block) ;
877+
878+ assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
879+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
880+
881+ // No data since can't read past end of file, only status byte length.
882+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
883+ assert_eq ! (
884+ mem. read_obj:: <u32 >( status_addr) . unwrap( ) ,
885+ VIRTIO_BLK_S_IOERR
886+ ) ;
794887 assert_eq ! ( mem. read_obj:: <u64 >( data_addr) . unwrap( ) , 123_456_789 ) ;
795888 }
889+
890+ {
891+ vq. used . idx . set ( 0 ) ;
892+ block. set_queue ( 0 , vq. create_queue ( ) ) ;
893+
894+ mem. write_obj :: < u32 > ( VIRTIO_BLK_T_IN , request_type_addr)
895+ . unwrap ( ) ;
896+ vq. dtable [ 1 ]
897+ . flags
898+ . set ( VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE ) ;
899+ vq. dtable [ 1 ] . len . set ( 1024 ) ;
900+
901+ mem. write_obj ( 1 , GuestAddress ( request_type_addr. 0 + 8 ) )
902+ . unwrap ( ) ;
903+
904+ invoke_handler_for_queue_event ( & mut block) ;
905+
906+ assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
907+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
908+
909+ // File has 2 sectors and we try to read from the second sector, which means we will
910+ // read 512 bytes (instead of 1024).
911+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 513 ) ;
912+ assert_eq ! (
913+ mem. read_obj:: <u32 >( status_addr) . unwrap( ) ,
914+ VIRTIO_BLK_S_IOERR
915+ ) ;
916+ }
796917 }
797918
798919 #[ test]
@@ -817,7 +938,7 @@ pub(crate) mod tests {
817938 invoke_handler_for_queue_event ( & mut block) ;
818939 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
819940 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
820- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
941+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
821942 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
822943 }
823944
@@ -833,7 +954,8 @@ pub(crate) mod tests {
833954 invoke_handler_for_queue_event ( & mut block) ;
834955 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
835956 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
836- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
957+ // status byte length.
958+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
837959 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
838960 }
839961 }
@@ -862,7 +984,7 @@ pub(crate) mod tests {
862984 invoke_handler_for_queue_event ( & mut block) ;
863985 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
864986 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
865- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
987+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 21 ) ;
866988 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
867989
868990 assert ! ( blk_metadata. is_ok( ) ) ;
@@ -973,7 +1095,7 @@ pub(crate) mod tests {
9731095 // Make sure the data queue advanced.
9741096 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
9751097 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
976- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
1098+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
9771099 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
9781100 }
9791101 }
@@ -1064,7 +1186,7 @@ pub(crate) mod tests {
10641186 // Make sure the data queue advanced.
10651187 assert_eq ! ( vq. used. idx. get( ) , 1 ) ;
10661188 assert_eq ! ( vq. used. ring[ 0 ] . get( ) . id, 0 ) ;
1067- assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 0 ) ;
1189+ assert_eq ! ( vq. used. ring[ 0 ] . get( ) . len, 1 ) ;
10681190 assert_eq ! ( mem. read_obj:: <u32 >( status_addr) . unwrap( ) , VIRTIO_BLK_S_OK ) ;
10691191 }
10701192 }
0 commit comments