@@ -60,6 +60,18 @@ struct SourceProtocol<T: AsyncRead + AsyncWrite + Unpin + Send> {
60
60
61
61
/// Transport to the destination Instance.
62
62
conn : WebSocketStream < T > ,
63
+
64
+ // TODO: A hacky way for now to hang onto the VMM timing data between
65
+ // migration phases.
66
+ //
67
+ // We want to read the VMM timing data as soon as we can after we pause the
68
+ // source, and make adjustments on the destination as close as we can to
69
+ // the end of the migration.
70
+ //
71
+ // This lets us hang on to the data between export in the pause phase,
72
+ // the send the data in the device_state phase, after the bulk of the
73
+ // migration time has passed.
74
+ vmm_data : Option < propolis:: vmm:: migrate:: BhyveVmV1 > ,
63
75
}
64
76
65
77
impl < T : AsyncRead + AsyncWrite + Unpin + Send > SourceProtocol < T > {
@@ -69,7 +81,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
69
81
response_rx : tokio:: sync:: mpsc:: Receiver < MigrateSourceResponse > ,
70
82
conn : WebSocketStream < T > ,
71
83
) -> Self {
72
- Self { vm_controller, command_tx, response_rx, conn }
84
+ Self { vm_controller, command_tx, response_rx, conn, vmm_data : None }
73
85
}
74
86
75
87
fn log ( & self ) -> & slog:: Logger {
@@ -233,16 +245,28 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
233
245
info ! ( self . log( ) , "Pausing devices" ) ;
234
246
self . command_tx . send ( MigrateSourceCommand :: Pause ) . await . unwrap ( ) ;
235
247
let resp = self . response_rx . recv ( ) . await . unwrap ( ) ;
236
- match resp {
237
- MigrateSourceResponse :: Pause ( Ok ( ( ) ) ) => Ok ( ( ) ) ,
238
- _ => {
239
- info ! (
240
- self . log( ) ,
241
- "Unexpected pause response from state worker: {:?}" , resp
242
- ) ;
243
- Err ( MigrateError :: SourcePause )
244
- }
248
+ if !matches ! ( resp, MigrateSourceResponse :: Pause ( Ok ( ( ) ) ) ) {
249
+ info ! (
250
+ self . log( ) ,
251
+ "Unexpected pause response from state worker: {:?}" , resp
252
+ ) ;
253
+ return Err ( MigrateError :: SourcePause ) ;
245
254
}
255
+
256
+ // Fetch the timing data values after we pause, but before lengthier
257
+ // migration steps, so we can correctly account for migration time in
258
+ // our adjustments.
259
+ self . timing_data_snapshot ( ) . await
260
+ }
261
+
262
+ async fn timing_data_snapshot ( & mut self ) -> Result < ( ) , MigrateError > {
263
+ let instance_guard = self . vm_controller . instance ( ) . lock ( ) ;
264
+ let vmm_hdl = & instance_guard. machine ( ) . hdl ;
265
+ let raw = vmm_hdl. export_vm ( ) ?;
266
+ self . vmm_data = Some ( raw) ;
267
+ info ! ( self . log( ) , "VMM State: {:#?}" , self . vmm_data) ;
268
+
269
+ Ok ( ( ) )
246
270
}
247
271
248
272
async fn device_state ( & mut self ) -> Result < ( ) , MigrateError > {
@@ -286,6 +310,14 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
286
310
. await ?;
287
311
288
312
self . send_msg ( codec:: Message :: Okay ) . await ?;
313
+ self . read_ok ( ) . await ?;
314
+
315
+ // Migrate VMM-wide data
316
+ let vmm_data = self . vmm_data . as_mut ( ) . unwrap ( ) ;
317
+ let vmm_state = ron:: ser:: to_string ( & vmm_data)
318
+ . map_err ( codec:: ProtocolError :: from) ?;
319
+ info ! ( self . log( ) , "VMM State: {:#?}" , vmm_state) ;
320
+ self . send_msg ( codec:: Message :: Serialized ( vmm_state) ) . await ?;
289
321
self . read_ok ( ) . await
290
322
}
291
323
0 commit comments