@@ -98,16 +98,29 @@ impl IoVecBuffer {
98
98
///
99
99
/// # Returns
100
100
///
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 > {
103
109
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 ( ( ) )
108
121
} else {
109
122
// If `offset` is past size, there's nothing to read.
110
- None
123
+ Err ( VolatileMemoryError :: OutOfBounds { addr : offset } )
111
124
}
112
125
}
113
126
@@ -223,15 +236,29 @@ impl IoVecBufferMut {
223
236
///
224
237
/// # Returns
225
238
///
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 > {
228
247
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 ( ( ) )
232
259
} else {
233
260
// We cannot write past the end of the `IoVecBufferMut`.
234
- None
261
+ Err ( VolatileMemoryError :: OutOfBounds { addr : offset } )
235
262
}
236
263
}
237
264
@@ -292,6 +319,7 @@ impl IoVecBufferMut {
292
319
#[ cfg( test) ]
293
320
mod tests {
294
321
use libc:: { c_void, iovec} ;
322
+ use vm_memory:: VolatileMemoryError ;
295
323
296
324
use super :: { IoVecBuffer , IoVecBufferMut } ;
297
325
use crate :: devices:: virtio:: queue:: { Queue , VIRTQ_DESC_F_NEXT , VIRTQ_DESC_F_WRITE } ;
@@ -397,7 +425,7 @@ mod tests {
397
425
let mem = default_mem ( ) ;
398
426
let ( mut q, _) = read_only_chain ( & mem) ;
399
427
let head = q. pop ( & mem) . unwrap ( ) ;
400
- assert ! ( IoVecBuffer :: from_descriptor_chain( head) . is_ok ( ) ) ;
428
+ IoVecBuffer :: from_descriptor_chain ( head) . unwrap ( ) ;
401
429
402
430
let ( mut q, _) = write_only_chain ( & mem) ;
403
431
let head = q. pop ( & mem) . unwrap ( ) ;
@@ -409,7 +437,7 @@ mod tests {
409
437
410
438
let ( mut q, _) = write_only_chain ( & mem) ;
411
439
let head = q. pop ( & mem) . unwrap ( ) ;
412
- assert ! ( IoVecBufferMut :: from_descriptor_chain( head) . is_ok ( ) ) ;
440
+ IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) ;
413
441
}
414
442
415
443
#[ test]
@@ -440,28 +468,48 @@ mod tests {
440
468
441
469
let iovec = IoVecBuffer :: from_descriptor_chain ( head) . unwrap ( ) ;
442
470
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
+ ) ;
445
478
assert_eq ! ( buf[ 0 ..256 ] , ( 0 ..=255 ) . collect:: <Vec <_>>( ) ) ;
446
479
assert_eq ! ( buf[ 256 ] , 0 ) ;
447
480
448
481
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 ( ) ;
450
483
assert_eq ! ( buf, vec![ 0u8 , 1 , 2 , 3 , 0 ] ) ;
451
484
452
- assert_eq ! ( iovec. read_at ( & mut buf, 0 ) , Some ( 5 ) ) ;
485
+ iovec. read_exact_volatile_at ( & mut buf, 0 ) . unwrap ( ) ;
453
486
assert_eq ! ( buf, vec![ 0u8 , 1 , 2 , 3 , 4 ] ) ;
454
487
455
- assert_eq ! ( iovec. read_at ( & mut buf, 1 ) , Some ( 5 ) ) ;
488
+ iovec. read_exact_volatile_at ( & mut buf, 1 ) . unwrap ( ) ;
456
489
assert_eq ! ( buf, vec![ 1u8 , 2 , 3 , 4 , 5 ] ) ;
457
490
458
- assert_eq ! ( iovec. read_at ( & mut buf, 60 ) , Some ( 5 ) ) ;
491
+ iovec. read_exact_volatile_at ( & mut buf, 60 ) . unwrap ( ) ;
459
492
assert_eq ! ( buf, vec![ 60u8 , 61 , 62 , 63 , 64 ] ) ;
460
493
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
+ ) ;
462
500
assert_eq ! ( buf[ 0 ..4 ] , vec![ 252u8 , 253 , 254 , 255 ] ) ;
463
501
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
+ ) ) ;
465
513
}
466
514
467
515
#[ test]
@@ -482,10 +530,10 @@ mod tests {
482
530
let mut test_vec4 = vec ! [ 0u8 ; 64 ] ;
483
531
484
532
// 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 ( ) ;
489
537
vq. dtable [ 0 ] . check_data ( & test_vec1) ;
490
538
vq. dtable [ 1 ] . check_data ( & test_vec2) ;
491
539
vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -494,7 +542,7 @@ mod tests {
494
542
// Let's initialize test_vec1 with our buffer.
495
543
test_vec1[ ..buf. len ( ) ] . copy_from_slice ( & buf) ;
496
544
// 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 ( ) ;
498
546
// Not all 5 bytes from buf should be written in memory,
499
547
// just 3 of them.
500
548
vq. dtable [ 0 ] . check_data ( & [ 0u8 , 1 , 2 , 0 , 0 ] ) ;
@@ -503,7 +551,7 @@ mod tests {
503
551
vq. dtable [ 3 ] . check_data ( & test_vec4) ;
504
552
// But if we write the whole `buf` in memory then all
505
553
// of it should be observable.
506
- assert_eq ! ( iovec. write_at ( & buf, 0 ) , Some ( 5 ) ) ;
554
+ iovec. write_all_volatile_at ( & buf, 0 ) . unwrap ( ) ;
507
555
vq. dtable [ 0 ] . check_data ( & test_vec1) ;
508
556
vq. dtable [ 1 ] . check_data ( & test_vec2) ;
509
557
vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -512,7 +560,7 @@ mod tests {
512
560
// We are now writing with an offset of 1. So, initialize
513
561
// the corresponding part of `test_vec1`
514
562
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 ( ) ;
516
564
vq. dtable [ 0 ] . check_data ( & test_vec1) ;
517
565
vq. dtable [ 1 ] . check_data ( & test_vec2) ;
518
566
vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -523,7 +571,7 @@ mod tests {
523
571
// first region and one byte on the second
524
572
test_vec1[ 60 ..64 ] . copy_from_slice ( & buf[ 0 ..4 ] ) ;
525
573
test_vec2[ 0 ] = 4 ;
526
- assert_eq ! ( iovec. write_at ( & buf, 60 ) , Some ( 5 ) ) ;
574
+ iovec. write_all_volatile_at ( & buf, 60 ) . unwrap ( ) ;
527
575
vq. dtable [ 0 ] . check_data ( & test_vec1) ;
528
576
vq. dtable [ 1 ] . check_data ( & test_vec2) ;
529
577
vq. dtable [ 2 ] . check_data ( & test_vec3) ;
@@ -535,14 +583,20 @@ mod tests {
535
583
// Now perform a write that does not fit in the buffer. Try writing
536
584
// 5 bytes at offset 252 (only 4 bytes left).
537
585
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
+ ) ;
539
590
vq. dtable [ 0 ] . check_data ( & test_vec1) ;
540
591
vq. dtable [ 1 ] . check_data ( & test_vec2) ;
541
592
vq. dtable [ 2 ] . check_data ( & test_vec3) ;
542
593
vq. dtable [ 3 ] . check_data ( & test_vec4) ;
543
594
544
595
// 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
+ ) ) ;
546
600
vq. dtable [ 0 ] . check_data ( & test_vec1) ;
547
601
vq. dtable [ 1 ] . check_data ( & test_vec2) ;
548
602
vq. dtable [ 2 ] . check_data ( & test_vec3) ;
0 commit comments