6
6
// found in the THIRD-PARTY file.
7
7
8
8
use std:: fs:: File ;
9
- use std:: io:: SeekFrom ;
9
+ use std:: io:: { Read , Seek , SeekFrom } ;
10
10
use std:: sync:: Arc ;
11
11
12
12
use serde:: { Deserialize , Serialize } ;
@@ -17,7 +17,10 @@ pub use vm_memory::{
17
17
Address , ByteValued , Bytes , FileOffset , GuestAddress , GuestMemory , GuestMemoryRegion ,
18
18
GuestUsize , MemoryRegionAddress , MmapRegion , address,
19
19
} ;
20
- use vm_memory:: { Error as VmMemoryError , GuestMemoryError , WriteVolatile } ;
20
+ use vm_memory:: {
21
+ Error as VmMemoryError , GuestMemoryError , ReadVolatile , VolatileMemoryError , VolatileSlice ,
22
+ WriteVolatile ,
23
+ } ;
21
24
use vmm_sys_util:: errno;
22
25
23
26
use crate :: DirtyBitmap ;
@@ -50,6 +53,58 @@ pub enum MemoryError {
50
53
OffsetTooLarge ,
51
54
}
52
55
56
+ /// Newtype that implements [`ReadVolatile`] and [`WriteVolatile`] if `T` implements `Read` or
57
+ /// `Write` respectively, by reading/writing using a bounce buffer, and memcpy-ing into the
58
+ /// [`VolatileSlice`].
59
+ #[ derive( Debug ) ]
60
+ pub struct MaybeBounce < T > ( pub T , pub bool ) ;
61
+
62
+ impl < T : ReadVolatile > ReadVolatile for MaybeBounce < T > {
63
+ fn read_volatile < B : BitmapSlice > (
64
+ & mut self ,
65
+ buf : & mut VolatileSlice < B > ,
66
+ ) -> Result < usize , VolatileMemoryError > {
67
+ if self . 1 {
68
+ let mut bbuf = vec ! [ 0 ; buf. len( ) ] ;
69
+ let n = self
70
+ . 0
71
+ . read_volatile ( & mut VolatileSlice :: from ( bbuf. as_mut_slice ( ) ) ) ?;
72
+ buf. copy_from ( & bbuf[ ..n] ) ;
73
+ Ok ( n)
74
+ } else {
75
+ self . 0 . read_volatile ( buf)
76
+ }
77
+ }
78
+ }
79
+
80
+ impl < T : WriteVolatile > WriteVolatile for MaybeBounce < T > {
81
+ fn write_volatile < B : BitmapSlice > (
82
+ & mut self ,
83
+ buf : & VolatileSlice < B > ,
84
+ ) -> Result < usize , VolatileMemoryError > {
85
+ if self . 1 {
86
+ let mut bbuf = vec ! [ 0 ; buf. len( ) ] ;
87
+ buf. copy_to ( bbuf. as_mut_slice ( ) ) ;
88
+ self . 0
89
+ . write_volatile ( & VolatileSlice :: from ( bbuf. as_mut_slice ( ) ) )
90
+ } else {
91
+ self . 0 . write_volatile ( buf)
92
+ }
93
+ }
94
+ }
95
+
96
+ impl < R : Read > Read for MaybeBounce < R > {
97
+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
98
+ self . 0 . read ( buf)
99
+ }
100
+ }
101
+
102
+ impl < S : Seek > Seek for MaybeBounce < S > {
103
+ fn seek ( & mut self , pos : SeekFrom ) -> std:: io:: Result < u64 > {
104
+ self . 0 . seek ( pos)
105
+ }
106
+ }
107
+
53
108
/// Creates a `Vec` of `GuestRegionMmap` with the given configuration
54
109
pub fn create (
55
110
regions : impl Iterator < Item = ( GuestAddress , usize ) > ,
@@ -346,6 +401,7 @@ mod tests {
346
401
347
402
use std:: collections:: HashMap ;
348
403
use std:: io:: { Read , Seek } ;
404
+ use std:: os:: fd:: AsFd ;
349
405
350
406
use vmm_sys_util:: tempfile:: TempFile ;
351
407
@@ -722,4 +778,35 @@ mod tests {
722
778
seals. insert ( memfd:: FileSeal :: SealGrow ) ;
723
779
memfd. add_seals ( & seals) . unwrap_err ( ) ;
724
780
}
781
+
782
+ #[ test]
783
+ fn test_bounce ( ) {
784
+ let file_direct = TempFile :: new ( ) . unwrap ( ) ;
785
+ let file_bounced = TempFile :: new ( ) . unwrap ( ) ;
786
+
787
+ let mut data = ( 0 ..=255 ) . collect :: < Vec < _ > > ( ) ;
788
+
789
+ MaybeBounce ( file_direct. as_file ( ) . as_fd ( ) , false )
790
+ . write_all_volatile ( & VolatileSlice :: from ( data. as_mut_slice ( ) ) )
791
+ . unwrap ( ) ;
792
+ MaybeBounce ( file_bounced. as_file ( ) . as_fd ( ) , true )
793
+ . write_all_volatile ( & VolatileSlice :: from ( data. as_mut_slice ( ) ) )
794
+ . unwrap ( ) ;
795
+
796
+ let mut data_direct = vec ! [ 0u8 ; 256 ] ;
797
+ let mut data_bounced = vec ! [ 0u8 ; 256 ] ;
798
+
799
+ file_direct. as_file ( ) . seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
800
+ file_bounced. as_file ( ) . seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
801
+
802
+ MaybeBounce ( file_direct. as_file ( ) . as_fd ( ) , false )
803
+ . read_exact_volatile ( & mut VolatileSlice :: from ( data_direct. as_mut_slice ( ) ) )
804
+ . unwrap ( ) ;
805
+ MaybeBounce ( file_bounced. as_file ( ) . as_fd ( ) , true )
806
+ . read_exact_volatile ( & mut VolatileSlice :: from ( data_bounced. as_mut_slice ( ) ) )
807
+ . unwrap ( ) ;
808
+
809
+ assert_eq ! ( data_direct, data_bounced) ;
810
+ assert_eq ! ( data_direct, data) ;
811
+ }
725
812
}
0 commit comments