22
33use std:: {
44 collections:: { HashMap , HashSet } ,
5- io:: { self , Result as IoResult } ,
5+ io:: { self , Result as IoResult , BufReader , Read } ,
66 path:: PathBuf ,
77 sync:: { Arc , Mutex , RwLock } ,
8+ fs:: File ,
9+ thread:: { self , JoinHandle } ,
810} ;
911
1012use log:: warn;
1113use thiserror:: Error as ThisError ;
12- use vhost:: vhost_user:: message:: { VhostUserProtocolFeatures , VhostUserVirtioFeatures } ;
14+ use vhost:: vhost_user:: message:: {
15+ VhostTransferStateDirection , VhostTransferStatePhase , VhostUserProtocolFeatures , VhostUserVirtioFeatures
16+ } ;
1317use vhost_user_backend:: { VhostUserBackend , VringRwLock } ;
1418use virtio_bindings:: bindings:: {
1519 virtio_config:: VIRTIO_F_NOTIFY_ON_EMPTY , virtio_config:: VIRTIO_F_VERSION_1 ,
@@ -252,12 +256,27 @@ struct VirtioVsockConfig {
252256// reading its content from byte array.
253257unsafe impl ByteValued for VirtioVsockConfig { }
254258
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+
255273pub ( crate ) struct VhostUserVsockBackend {
256274 config : VirtioVsockConfig ,
257275 queue_size : usize ,
258276 pub threads : Vec < Mutex < VhostUserVsockThread > > ,
259277 queues_per_thread : Vec < u64 > ,
260278 pub exit_event : EventFd ,
279+ pub handler_thread : Mutex < HandlerThread > ,
261280}
262281
263282impl VhostUserVsockBackend {
@@ -279,6 +298,7 @@ impl VhostUserVsockBackend {
279298 threads : vec ! [ thread] ,
280299 queues_per_thread,
281300 exit_event : EventFd :: new ( EFD_NONBLOCK ) . map_err ( Error :: EventFdCreate ) ?,
301+ handler_thread : Mutex :: new ( HandlerThread :: new ( None , false ) ?) ,
282302 } )
283303 }
284304}
@@ -303,7 +323,54 @@ impl VhostUserBackend for VhostUserVsockBackend {
303323 }
304324
305325 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 ( ( ) ) ;
307374 }
308375
309376 fn set_event_idx ( & self , enabled : bool ) {
0 commit comments