@@ -64,54 +64,123 @@ pub enum MemoryError {
6464/// `Write` respectively, by reading/writing using a bounce buffer, and memcpy-ing into the
6565/// [`VolatileSlice`].
6666#[ derive( Debug ) ]
67- pub struct MaybeBounce < T > ( pub T , pub bool ) ;
67+ pub struct MaybeBounce < T , const N : usize = 0 > {
68+ pub ( crate ) target : T ,
69+ pub ( crate ) should_bounce : bool ,
70+ persistent_buffer : [ u8 ; N ] ,
71+ }
72+
73+ impl < T > MaybeBounce < T , 0 > {
74+ /// Creates a new `MaybeBounce` that always allocates a bounce
75+ /// buffer on-demand
76+ pub fn new ( target : T , should_bounce : bool ) -> Self {
77+ MaybeBounce :: new_persistent ( target, should_bounce)
78+ }
79+ }
80+
81+ impl < T , const N : usize > MaybeBounce < T , N > {
82+ /// Creates a new `MaybeBounce` that uses a persistent, fixed size bounce buffer
83+ /// of size `N`. If a read/write request exceeds the size of this bounce buffer, it
84+ /// is split into multiple, `<= N`-size read/writes.
85+ pub fn new_persistent ( target : T , should_bounce : bool ) -> Self {
86+ MaybeBounce {
87+ target,
88+ should_bounce,
89+ persistent_buffer : [ 0u8 ; N ] ,
90+ }
91+ }
92+ }
6893
6994// FIXME: replace AsFd with ReadVolatile once &File: ReadVolatile in vm-memory.
70- impl < T : Read + AsFd > ReadVolatile for MaybeBounce < T > {
95+ impl < T : Read + AsFd , const N : usize > ReadVolatile for MaybeBounce < T , N > {
7196 fn read_volatile < B : BitmapSlice > (
7297 & mut self ,
7398 buf : & mut VolatileSlice < B > ,
7499 ) -> Result < usize , VolatileMemoryError > {
75- if self . 1 {
76- let mut bbuf = vec ! [ 0 ; buf. len( ) ] ;
77- let n = self
78- . 0
79- . read ( bbuf. as_mut_slice ( ) )
80- . map_err ( VolatileMemoryError :: IOError ) ?;
81- buf. copy_from ( & bbuf[ ..n] ) ;
82- Ok ( n)
100+ if self . should_bounce {
101+ let mut bbuf = ( N == 0 ) . then ( || vec ! [ 0u8 ; buf. len( ) ] ) ;
102+ let bbuf = bbuf
103+ . as_deref_mut ( )
104+ . unwrap_or ( self . persistent_buffer . as_mut_slice ( ) ) ;
105+
106+ let mut buf = buf. offset ( 0 ) ?;
107+ let mut total = 0 ;
108+ while !buf. is_empty ( ) {
109+ let how_much = buf. len ( ) . min ( bbuf. len ( ) ) ;
110+ let n = self
111+ . target
112+ . read ( & mut bbuf[ ..how_much] )
113+ . map_err ( VolatileMemoryError :: IOError ) ?;
114+ buf. copy_from ( & bbuf[ ..n] ) ;
115+
116+ buf = buf. offset ( n) ?;
117+ total += n;
118+
119+ if n < how_much {
120+ break ;
121+ }
122+ }
123+
124+ Ok ( total)
83125 } else {
84- self . 0 . as_fd ( ) . read_volatile ( buf)
126+ self . target . as_fd ( ) . read_volatile ( buf)
85127 }
86128 }
87129}
88130
89- impl < T : Write + AsFd > WriteVolatile for MaybeBounce < T > {
131+ impl < T : Write + AsFd , const N : usize > WriteVolatile for MaybeBounce < T , N > {
90132 fn write_volatile < B : BitmapSlice > (
91133 & mut self ,
92134 buf : & VolatileSlice < B > ,
93135 ) -> Result < usize , VolatileMemoryError > {
94- if self . 1 {
95- let mut bbuf = vec ! [ 0 ; buf. len( ) ] ;
96- buf. copy_to ( bbuf. as_mut_slice ( ) ) ;
97- self . 0
98- . write ( bbuf. as_slice ( ) )
99- . map_err ( VolatileMemoryError :: IOError )
136+ if self . should_bounce {
137+ let mut bbuf = ( N == 0 ) . then ( || vec ! [ 0u8 ; buf. len( ) ] ) ;
138+ let bbuf = bbuf
139+ . as_deref_mut ( )
140+ . unwrap_or ( self . persistent_buffer . as_mut_slice ( ) ) ;
141+
142+ let mut buf = buf. offset ( 0 ) ?;
143+ let mut total = 0 ;
144+ while !buf. is_empty ( ) {
145+ let how_much = buf. copy_to ( bbuf) ;
146+ let n = self
147+ . target
148+ . write ( & bbuf[ ..how_much] )
149+ . map_err ( VolatileMemoryError :: IOError ) ?;
150+ buf = buf. offset ( n) ?;
151+ total += n;
152+
153+ if n < how_much {
154+ break ;
155+ }
156+ }
157+
158+ Ok ( total)
100159 } else {
101- self . 0 . as_fd ( ) . write_volatile ( buf)
160+ self . target . as_fd ( ) . write_volatile ( buf)
102161 }
103162 }
104163}
105164
106- impl < R : Read > Read for MaybeBounce < R > {
165+ impl < R : Read , const N : usize > Read for MaybeBounce < R , N > {
107166 fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
108- self . 0 . read ( buf)
167+ self . target . read ( buf)
168+ }
169+ }
170+
171+ impl < W : Write , const N : usize > Write for MaybeBounce < W , N > {
172+ fn write ( & mut self , buf : & [ u8 ] ) -> std:: io:: Result < usize > {
173+ self . target . write ( buf)
174+ }
175+
176+ fn flush ( & mut self ) -> std:: io:: Result < ( ) > {
177+ self . target . flush ( )
109178 }
110179}
111180
112- impl < S : Seek > Seek for MaybeBounce < S > {
181+ impl < S : Seek , const N : usize > Seek for MaybeBounce < S , N > {
113182 fn seek ( & mut self , pos : SeekFrom ) -> std:: io:: Result < u64 > {
114- self . 0 . seek ( pos)
183+ self . target . seek ( pos)
115184 }
116185}
117186
@@ -947,30 +1016,45 @@ mod tests {
9471016 fn test_bounce ( ) {
9481017 let file_direct = TempFile :: new ( ) . unwrap ( ) ;
9491018 let file_bounced = TempFile :: new ( ) . unwrap ( ) ;
1019+ let file_persistent_bounced = TempFile :: new ( ) . unwrap ( ) ;
9501020
9511021 let mut data = ( 0 ..=255 ) . collect_vec ( ) ;
9521022
953- MaybeBounce ( file_direct. as_file ( ) , false )
1023+ MaybeBounce :: new ( file_direct. as_file ( ) , false )
1024+ . write_all_volatile ( & VolatileSlice :: from ( data. as_mut_slice ( ) ) )
1025+ . unwrap ( ) ;
1026+ MaybeBounce :: new ( file_bounced. as_file ( ) , true )
9541027 . write_all_volatile ( & VolatileSlice :: from ( data. as_mut_slice ( ) ) )
9551028 . unwrap ( ) ;
956- MaybeBounce ( file_bounced . as_file ( ) , true )
1029+ MaybeBounce :: < _ , 7 > :: new_persistent ( file_persistent_bounced . as_file ( ) , true )
9571030 . write_all_volatile ( & VolatileSlice :: from ( data. as_mut_slice ( ) ) )
9581031 . unwrap ( ) ;
9591032
9601033 let mut data_direct = vec ! [ 0u8 ; 256 ] ;
9611034 let mut data_bounced = vec ! [ 0u8 ; 256 ] ;
1035+ let mut data_persistent_bounced = vec ! [ 0u8 ; 256 ] ;
9621036
9631037 file_direct. as_file ( ) . seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
9641038 file_bounced. as_file ( ) . seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
1039+ file_persistent_bounced
1040+ . as_file ( )
1041+ . seek ( SeekFrom :: Start ( 0 ) )
1042+ . unwrap ( ) ;
9651043
966- MaybeBounce ( file_direct. as_file ( ) , false )
1044+ MaybeBounce :: new ( file_direct. as_file ( ) , false )
9671045 . read_exact_volatile ( & mut VolatileSlice :: from ( data_direct. as_mut_slice ( ) ) )
9681046 . unwrap ( ) ;
969- MaybeBounce ( file_bounced. as_file ( ) , true )
1047+ MaybeBounce :: new ( file_bounced. as_file ( ) , true )
9701048 . read_exact_volatile ( & mut VolatileSlice :: from ( data_bounced. as_mut_slice ( ) ) )
9711049 . unwrap ( ) ;
1050+ MaybeBounce :: < _ , 7 > :: new_persistent ( file_persistent_bounced. as_file ( ) , true )
1051+ . read_exact_volatile ( & mut VolatileSlice :: from (
1052+ data_persistent_bounced. as_mut_slice ( ) ,
1053+ ) )
1054+ . unwrap ( ) ;
9721055
9731056 assert_eq ! ( data_direct, data_bounced) ;
9741057 assert_eq ! ( data_direct, data) ;
1058+ assert_eq ! ( data_persistent_bounced, data) ;
9751059 }
9761060}
0 commit comments