66// found in the THIRD-PARTY file.
77
88use std:: fs:: File ;
9- use std:: io:: SeekFrom ;
9+ use std:: io:: { Read , Seek , SeekFrom } ;
1010use std:: sync:: Arc ;
1111
1212use serde:: { Deserialize , Serialize } ;
@@ -17,7 +17,10 @@ pub use vm_memory::{
1717 Address , ByteValued , Bytes , FileOffset , GuestAddress , GuestMemory , GuestMemoryRegion ,
1818 GuestUsize , MemoryRegionAddress , MmapRegion , address,
1919} ;
20- use vm_memory:: { Error as VmMemoryError , GuestMemoryError , WriteVolatile } ;
20+ use vm_memory:: {
21+ Error as VmMemoryError , GuestMemoryError , ReadVolatile , VolatileMemoryError , VolatileSlice ,
22+ WriteVolatile ,
23+ } ;
2124use vmm_sys_util:: errno;
2225
2326use crate :: DirtyBitmap ;
@@ -50,6 +53,59 @@ pub enum MemoryError {
5053 OffsetTooLarge ,
5154}
5255
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+ // FIXME: replace AsFd with ReadVolatile once &File: ReadVolatile in vm-memory.
63+ impl < T : ReadVolatile > ReadVolatile for MaybeBounce < T > {
64+ fn read_volatile < B : BitmapSlice > (
65+ & mut self ,
66+ buf : & mut VolatileSlice < B > ,
67+ ) -> Result < usize , VolatileMemoryError > {
68+ if self . 1 {
69+ let mut bbuf = vec ! [ 0 ; buf. len( ) ] ;
70+ let n = self
71+ . 0
72+ . read_volatile ( & mut VolatileSlice :: from ( bbuf. as_mut_slice ( ) ) ) ?;
73+ buf. copy_from ( & bbuf[ ..n] ) ;
74+ Ok ( n)
75+ } else {
76+ self . 0 . read_volatile ( buf)
77+ }
78+ }
79+ }
80+
81+ impl < T : WriteVolatile > WriteVolatile for MaybeBounce < T > {
82+ fn write_volatile < B : BitmapSlice > (
83+ & mut self ,
84+ buf : & VolatileSlice < B > ,
85+ ) -> Result < usize , VolatileMemoryError > {
86+ if self . 1 {
87+ let mut bbuf = vec ! [ 0 ; buf. len( ) ] ;
88+ buf. copy_to ( bbuf. as_mut_slice ( ) ) ;
89+ self . 0
90+ . write_volatile ( & VolatileSlice :: from ( bbuf. as_mut_slice ( ) ) )
91+ } else {
92+ self . 0 . write_volatile ( buf)
93+ }
94+ }
95+ }
96+
97+ impl < R : Read > Read for MaybeBounce < R > {
98+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
99+ self . 0 . read ( buf)
100+ }
101+ }
102+
103+ impl < S : Seek > Seek for MaybeBounce < S > {
104+ fn seek ( & mut self , pos : SeekFrom ) -> std:: io:: Result < u64 > {
105+ self . 0 . seek ( pos)
106+ }
107+ }
108+
53109/// Creates a `Vec` of `GuestRegionMmap` with the given configuration
54110pub fn create (
55111 regions : impl Iterator < Item = ( GuestAddress , usize ) > ,
@@ -346,7 +402,7 @@ mod tests {
346402
347403 use std:: collections:: HashMap ;
348404 use std:: io:: { Read , Seek } ;
349-
405+ use std :: os :: fd :: AsFd ;
350406 use vmm_sys_util:: tempfile:: TempFile ;
351407
352408 use super :: * ;
@@ -722,4 +778,35 @@ mod tests {
722778 seals. insert ( memfd:: FileSeal :: SealGrow ) ;
723779 memfd. add_seals ( & seals) . unwrap_err ( ) ;
724780 }
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+ }
725812}
0 commit comments