2
2
3
3
use std:: {
4
4
collections:: { HashMap , HashSet } ,
5
- io:: { self , Result as IoResult } ,
5
+ io:: { self , Result as IoResult , BufReader , Read } ,
6
6
path:: PathBuf ,
7
7
sync:: { Arc , Mutex , RwLock } ,
8
+ fs:: File ,
9
+ thread:: { self , JoinHandle } ,
8
10
} ;
9
11
10
12
use log:: warn;
11
13
use thiserror:: Error as ThisError ;
12
- use vhost:: vhost_user:: message:: { VhostUserProtocolFeatures , VhostUserVirtioFeatures } ;
14
+ use vhost:: vhost_user:: message:: {
15
+ VhostTransferStateDirection , VhostTransferStatePhase , VhostUserProtocolFeatures , VhostUserVirtioFeatures
16
+ } ;
13
17
use vhost_user_backend:: { VhostUserBackend , VringRwLock } ;
14
18
use virtio_bindings:: bindings:: {
15
19
virtio_config:: VIRTIO_F_NOTIFY_ON_EMPTY , virtio_config:: VIRTIO_F_VERSION_1 ,
@@ -252,12 +256,27 @@ struct VirtioVsockConfig {
252
256
// reading its content from byte array.
253
257
unsafe impl ByteValued for VirtioVsockConfig { }
254
258
259
+ pub ( crate ) struct HandlerThread {
260
+ pub handle : Option < JoinHandle < ( ) > > ,
261
+ pub created : bool ,
262
+ }
263
+
264
+ impl HandlerThread {
265
+ pub fn new ( handle : Option < JoinHandle < ( ) > > , created : bool ) -> Result < Self > {
266
+ Ok ( Self {
267
+ handle : handle,
268
+ created : created,
269
+ } )
270
+ }
271
+ }
272
+
255
273
pub ( crate ) struct VhostUserVsockBackend {
256
274
config : VirtioVsockConfig ,
257
275
queue_size : usize ,
258
276
pub threads : Vec < Mutex < VhostUserVsockThread > > ,
259
277
queues_per_thread : Vec < u64 > ,
260
278
pub exit_event : EventFd ,
279
+ pub handler_thread : Mutex < HandlerThread > ,
261
280
}
262
281
263
282
impl VhostUserVsockBackend {
@@ -279,6 +298,7 @@ impl VhostUserVsockBackend {
279
298
threads : vec ! [ thread] ,
280
299
queues_per_thread,
281
300
exit_event : EventFd :: new ( EFD_NONBLOCK ) . map_err ( Error :: EventFdCreate ) ?,
301
+ handler_thread : Mutex :: new ( HandlerThread :: new ( None , false ) ?) ,
282
302
} )
283
303
}
284
304
}
@@ -303,7 +323,54 @@ impl VhostUserBackend for VhostUserVsockBackend {
303
323
}
304
324
305
325
fn protocol_features ( & self ) -> VhostUserProtocolFeatures {
306
- VhostUserProtocolFeatures :: MQ | VhostUserProtocolFeatures :: CONFIG
326
+ VhostUserProtocolFeatures :: MQ | VhostUserProtocolFeatures :: CONFIG | VhostUserProtocolFeatures :: DEVICE_STATE
327
+ }
328
+
329
+ fn set_device_state_fd (
330
+ & self ,
331
+ direction : VhostTransferStateDirection ,
332
+ phase : VhostTransferStatePhase ,
333
+ file : File ,
334
+ ) -> IoResult < Option < File > > {
335
+ self . handler_thread . lock ( ) . unwrap ( ) . created = true ;
336
+ let handle = thread:: spawn ( move || {
337
+ match direction {
338
+ SAVE => {
339
+ // save
340
+ // No device state to save yet, just close the FD.
341
+ drop ( file) ;
342
+ }
343
+ LOAD => {
344
+ // load
345
+ // No device state to load yet, just verify it is empty.
346
+ let mut data = Vec :: new ( ) ;
347
+ let mut reader = BufReader :: new ( file) ;
348
+ if reader. read_to_end ( & mut data) . is_err ( ) {
349
+ println ! ( "vhost-device-vsock loaded device state read failed" ) ;
350
+ return ;
351
+ }
352
+
353
+ if data. len ( ) > 0 {
354
+ println ! ( "vhost-device-vsock loaded device state is non-empty. BUG!" ) ;
355
+ return ;
356
+ }
357
+ }
358
+ _ => {
359
+ println ! ( "invalid transfer_direction" ) ;
360
+ return ;
361
+ }
362
+ }
363
+ } ) ;
364
+ self . handler_thread . lock ( ) . unwrap ( ) . handle = Some ( handle) ;
365
+ return Ok ( None ) ;
366
+ }
367
+
368
+ fn check_device_state ( & self ) -> IoResult < ( ) > {
369
+ if ( self . handler_thread . lock ( ) . unwrap ( ) . created ) {
370
+ self . handler_thread . lock ( ) . unwrap ( ) . created = false ;
371
+ self . handler_thread . lock ( ) . unwrap ( ) . handle . take ( ) . unwrap ( ) . join ( ) . unwrap ( ) ;
372
+ }
373
+ return Ok ( ( ) ) ;
307
374
}
308
375
309
376
fn set_event_idx ( & self , enabled : bool ) {
0 commit comments