@@ -98,16 +98,29 @@ impl IoVecBuffer {
9898 ///
9999 /// # Returns
100100 ///
101- /// The number of bytes read (if any)
102- pub fn read_at ( & self , mut buf : & mut [ u8 ] , offset : usize ) -> Option < usize > {
101+ /// `Ok(())` if `buf` was filled by reading from this [`IoVecBuffer`],
102+ /// `Err(VolatileMemoryError::PartialBuffer)` if only part of `buf` could not be filled, and
103+ /// `Err(VolatileMemoryError::OutOfBounds)` if `offset >= self.len()`.
104+ pub fn read_exact_volatile_at (
105+ & self ,
106+ mut buf : & mut [ u8 ] ,
107+ offset : usize ,
108+ ) -> Result < ( ) , VolatileMemoryError > {
103109 if offset < self . len ( ) {
104- // Make sure we only read up to the end of the `IoVecBuffer`.
105- let size = buf. len ( ) . min ( self . len ( ) - offset) ;
106- // write_volatile for &mut [u8] is infallible
107- self . read_volatile_at ( & mut buf, offset, size) . ok ( )
110+ let expected = buf. len ( ) ;
111+ let bytes_read = self . read_volatile_at ( & mut buf, offset, expected) ?;
112+
113+ if bytes_read != expected {
114+ return Err ( VolatileMemoryError :: PartialBuffer {
115+ expected,
116+ completed : bytes_read,
117+ } ) ;
118+ }
119+
120+ Ok ( ( ) )
108121 } else {
109122 // If `offset` is past size, there's nothing to read.
110- None
123+ Err ( VolatileMemoryError :: OutOfBounds { addr : offset } )
111124 }
112125 }
113126
@@ -223,15 +236,29 @@ impl IoVecBufferMut {
223236 ///
224237 /// # Returns
225238 ///
226- /// The number of bytes written (if any)
227- pub fn write_at ( & mut self , mut buf : & [ u8 ] , offset : usize ) -> Option < usize > {
239+ /// `Ok(())` if the entire contents of `buf` could be written to this [`IoVecBufferMut`],
240+ /// `Err(VolatileMemoryError::PartialBuffer)` if only part of `buf` could be transferred, and
241+ /// `Err(VolatileMemoryError::OutOfBounds)` if `offset >= self.len()`.
242+ pub fn write_all_volatile_at (
243+ & mut self ,
244+ mut buf : & [ u8 ] ,
245+ offset : usize ,
246+ ) -> Result < ( ) , VolatileMemoryError > {
228247 if offset < self . len ( ) {
229- // Make sure we only write up to the end of the `IoVecBufferMut`.
230- let size = buf. len ( ) . min ( self . len ( ) - offset) ;
231- self . write_volatile_at ( & mut buf, offset, size) . ok ( )
248+ let expected = buf. len ( ) ;
249+ let bytes_written = self . write_volatile_at ( & mut buf, offset, expected) ?;
250+
251+ if bytes_written != expected {
252+ return Err ( VolatileMemoryError :: PartialBuffer {
253+ expected,
254+ completed : bytes_written,
255+ } ) ;
256+ }
257+
258+ Ok ( ( ) )
232259 } else {
233260 // We cannot write past the end of the `IoVecBufferMut`.
234- None
261+ Err ( VolatileMemoryError :: OutOfBounds { addr : offset } )
235262 }
236263 }
237264
@@ -292,6 +319,7 @@ impl IoVecBufferMut {
292319#[ cfg( test) ]
293320mod tests {
294321 use libc:: { c_void, iovec} ;
322+ use vm_memory:: VolatileMemoryError ;
295323
296324 use super :: { IoVecBuffer , IoVecBufferMut } ;
297325 use crate :: devices:: virtio:: queue:: { Queue , VIRTQ_DESC_F_NEXT , VIRTQ_DESC_F_WRITE } ;
@@ -397,7 +425,7 @@ mod tests {
397425 let mem = default_mem ( ) ;
398426 let ( mut q, _) = read_only_chain ( & mem) ;
399427 let head = q. pop ( & mem) . unwrap ( ) ;
400- assert ! ( IoVecBuffer :: from_descriptor_chain( head) . is_ok ( ) ) ;
428+ IoVecBuffer :: from_descriptor_chain ( head) . unwrap ( ) ;
401429
402430 let ( mut q, _) = write_only_chain ( & mem) ;
403431 let head = q. pop ( & mem) . unwrap ( ) ;
@@ -409,7 +437,7 @@ mod tests {
409437
410438 let ( mut q, _) = write_only_chain ( & mem) ;
411439 let head = q. pop ( & mem) . unwrap ( ) ;
412- assert ! ( IoVecBufferMut :: from_descriptor_chain( head) . is_ok ( ) ) ;
440+ IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) ;
413441 }
414442
415443 #[ test]
@@ -440,28 +468,48 @@ mod tests {
440468
441469 let iovec = IoVecBuffer :: from_descriptor_chain ( head) . unwrap ( ) ;
442470
443- let mut buf = vec ! [ 0 ; 257 ] ;
444- assert_eq ! ( iovec. read_at( & mut buf[ ..] , 0 ) , Some ( 256 ) ) ;
471+ let mut buf = vec ! [ 0u8 ; 257 ] ;
472+ assert_eq ! (
473+ iovec
474+ . read_volatile_at( & mut buf. as_mut_slice( ) , 0 , 257 )
475+ . unwrap( ) ,
476+ 256
477+ ) ;
445478 assert_eq ! ( buf[ 0 ..256 ] , ( 0 ..=255 ) . collect:: <Vec <_>>( ) ) ;
446479 assert_eq ! ( buf[ 256 ] , 0 ) ;
447480
448481 let mut buf = vec ! [ 0 ; 5 ] ;
449- assert_eq ! ( iovec. read_at ( & mut buf[ ..4 ] , 0 ) , Some ( 4 ) ) ;
482+ iovec. read_exact_volatile_at ( & mut buf[ ..4 ] , 0 ) . unwrap ( ) ;
450483 assert_eq ! ( buf, vec![ 0u8 , 1 , 2 , 3 , 0 ] ) ;
451484
452- assert_eq ! ( iovec. read_at ( & mut buf, 0 ) , Some ( 5 ) ) ;
485+ iovec. read_exact_volatile_at ( & mut buf, 0 ) . unwrap ( ) ;
453486 assert_eq ! ( buf, vec![ 0u8 , 1 , 2 , 3 , 4 ] ) ;
454487
455- assert_eq ! ( iovec. read_at ( & mut buf, 1 ) , Some ( 5 ) ) ;
488+ iovec. read_exact_volatile_at ( & mut buf, 1 ) . unwrap ( ) ;
456489 assert_eq ! ( buf, vec![ 1u8 , 2 , 3 , 4 , 5 ] ) ;
457490
458- assert_eq ! ( iovec. read_at ( & mut buf, 60 ) , Some ( 5 ) ) ;
491+ iovec. read_exact_volatile_at ( & mut buf, 60 ) . unwrap ( ) ;
459492 assert_eq ! ( buf, vec![ 60u8 , 61 , 62 , 63 , 64 ] ) ;
460493
461- assert_eq ! ( iovec. read_at( & mut buf, 252 ) , Some ( 4 ) ) ;
494+ assert_eq ! (
495+ iovec
496+ . read_volatile_at( & mut buf. as_mut_slice( ) , 252 , 5 )
497+ . unwrap( ) ,
498+ 4
499+ ) ;
462500 assert_eq ! ( buf[ 0 ..4 ] , vec![ 252u8 , 253 , 254 , 255 ] ) ;
463501
464- assert_eq ! ( iovec. read_at( & mut buf, 256 ) , None ) ;
502+ assert ! ( matches!(
503+ iovec. read_exact_volatile_at( & mut buf, 252 ) ,
504+ Err ( VolatileMemoryError :: PartialBuffer {
505+ expected: 5 ,
506+ completed: 4
507+ } )
508+ ) ) ;
509+ assert ! ( matches!(
510+ iovec. read_exact_volatile_at( & mut buf, 256 ) ,
511+ Err ( VolatileMemoryError :: OutOfBounds { addr: 256 } )
512+ ) ) ;
465513 }
466514
467515 #[ test]
@@ -482,10 +530,10 @@ mod tests {
482530 let mut test_vec4 = vec ! [ 0u8 ; 64 ] ;
483531
484532 // Control test: Initially all three regions should be zero
485- assert_eq ! ( iovec. write_at ( & test_vec1, 0 ) , Some ( 64 ) ) ;
486- assert_eq ! ( iovec. write_at ( & test_vec2, 64 ) , Some ( 64 ) ) ;
487- assert_eq ! ( iovec. write_at ( & test_vec3, 128 ) , Some ( 64 ) ) ;
488- assert_eq ! ( iovec. write_at ( & test_vec4, 192 ) , Some ( 64 ) ) ;
533+ iovec. write_all_volatile_at ( & test_vec1, 0 ) . unwrap ( ) ;
534+ iovec. write_all_volatile_at ( & test_vec2, 64 ) . unwrap ( ) ;
535+ iovec. write_all_volatile_at ( & test_vec3, 128 ) . unwrap ( ) ;
536+ iovec. write_all_volatile_at ( & test_vec4, 192 ) . unwrap ( ) ;
489537 vq. dtable [ 0 ] . check_data ( & test_vec1) ;
490538 vq. dtable [ 1 ] . check_data ( & test_vec2) ;
491539 vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -494,7 +542,7 @@ mod tests {
494542 // Let's initialize test_vec1 with our buffer.
495543 test_vec1[ ..buf. len ( ) ] . copy_from_slice ( & buf) ;
496544 // And write just a part of it
497- assert_eq ! ( iovec. write_at ( & buf[ ..3 ] , 0 ) , Some ( 3 ) ) ;
545+ iovec. write_all_volatile_at ( & buf[ ..3 ] , 0 ) . unwrap ( ) ;
498546 // Not all 5 bytes from buf should be written in memory,
499547 // just 3 of them.
500548 vq. dtable [ 0 ] . check_data ( & [ 0u8 , 1 , 2 , 0 , 0 ] ) ;
@@ -503,7 +551,7 @@ mod tests {
503551 vq. dtable [ 3 ] . check_data ( & test_vec4) ;
504552 // But if we write the whole `buf` in memory then all
505553 // of it should be observable.
506- assert_eq ! ( iovec. write_at ( & buf, 0 ) , Some ( 5 ) ) ;
554+ iovec. write_all_volatile_at ( & buf, 0 ) . unwrap ( ) ;
507555 vq. dtable [ 0 ] . check_data ( & test_vec1) ;
508556 vq. dtable [ 1 ] . check_data ( & test_vec2) ;
509557 vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -512,7 +560,7 @@ mod tests {
512560 // We are now writing with an offset of 1. So, initialize
513561 // the corresponding part of `test_vec1`
514562 test_vec1[ 1 ..buf. len ( ) + 1 ] . copy_from_slice ( & buf) ;
515- assert_eq ! ( iovec. write_at ( & buf, 1 ) , Some ( 5 ) ) ;
563+ iovec. write_all_volatile_at ( & buf, 1 ) . unwrap ( ) ;
516564 vq. dtable [ 0 ] . check_data ( & test_vec1) ;
517565 vq. dtable [ 1 ] . check_data ( & test_vec2) ;
518566 vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -523,7 +571,7 @@ mod tests {
523571 // first region and one byte on the second
524572 test_vec1[ 60 ..64 ] . copy_from_slice ( & buf[ 0 ..4 ] ) ;
525573 test_vec2[ 0 ] = 4 ;
526- assert_eq ! ( iovec. write_at ( & buf, 60 ) , Some ( 5 ) ) ;
574+ iovec. write_all_volatile_at ( & buf, 60 ) . unwrap ( ) ;
527575 vq. dtable [ 0 ] . check_data ( & test_vec1) ;
528576 vq. dtable [ 1 ] . check_data ( & test_vec2) ;
529577 vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -535,14 +583,20 @@ mod tests {
535583 // Now perform a write that does not fit in the buffer. Try writing
536584 // 5 bytes at offset 252 (only 4 bytes left).
537585 test_vec4[ 60 ..64 ] . copy_from_slice ( & buf[ 0 ..4 ] ) ;
538- assert_eq ! ( iovec. write_at( & buf, 252 ) , Some ( 4 ) ) ;
586+ assert_eq ! (
587+ iovec. write_volatile_at( & mut & * buf, 252 , buf. len( ) ) . unwrap( ) ,
588+ 4
589+ ) ;
539590 vq. dtable [ 0 ] . check_data ( & test_vec1) ;
540591 vq. dtable [ 1 ] . check_data ( & test_vec2) ;
541592 vq. dtable [ 2 ] . check_data ( & test_vec3) ;
542593 vq. dtable [ 3 ] . check_data ( & test_vec4) ;
543594
544595 // Trying to add past the end of the buffer should not write anything
545- assert_eq ! ( iovec. write_at( & buf, 256 ) , None ) ;
596+ assert ! ( matches!(
597+ iovec. write_all_volatile_at( & buf, 256 ) ,
598+ Err ( VolatileMemoryError :: OutOfBounds { addr: 256 } )
599+ ) ) ;
546600 vq. dtable [ 0 ] . check_data ( & test_vec1) ;
547601 vq. dtable [ 1 ] . check_data ( & test_vec2) ;
548602 vq. dtable [ 2 ] . check_data ( & test_vec3) ;
0 commit comments