diff --git a/vhost-device-vsock/Cargo.toml b/vhost-device-vsock/Cargo.toml index 19179ca0..7bf4f1dd 100644 --- a/vhost-device-vsock/Cargo.toml +++ b/vhost-device-vsock/Cargo.toml @@ -21,7 +21,7 @@ env_logger = "0.11" epoll = "4.3.2" log = "0.4" thiserror = "2.0" -vhost = { version = "0.13", features = ["vhost-user-backend"] } +vhost = { git = "https://github.com/WeiChungHsu/vhost.git", branch = "main", features = ["vhost-user-backend"] } vhost-user-backend = "0.17" virtio-bindings = "0.2.5" virtio-queue = "0.14" diff --git a/vhost-device-vsock/src/vhu_vsock.rs b/vhost-device-vsock/src/vhu_vsock.rs index 640084e7..7a5a64bc 100644 --- a/vhost-device-vsock/src/vhu_vsock.rs +++ b/vhost-device-vsock/src/vhu_vsock.rs @@ -2,14 +2,19 @@ use std::{ collections::{HashMap, HashSet}, - io::{self, Result as IoResult}, + fs::File, + io::{self, BufReader, Read, Result as IoResult}, path::PathBuf, sync::{Arc, Mutex, RwLock}, + thread::{self, JoinHandle}, }; use log::warn; use thiserror::Error as ThisError; -use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; +use vhost::vhost_user::message::{ + VhostTransferStateDirection, VhostTransferStatePhase, VhostUserProtocolFeatures, + VhostUserVirtioFeatures +}; use vhost_user_backend::{VhostUserBackend, VringRwLock}; use virtio_bindings::bindings::{ virtio_config::VIRTIO_F_NOTIFY_ON_EMPTY, virtio_config::VIRTIO_F_VERSION_1, @@ -258,6 +263,7 @@ pub(crate) struct VhostUserVsockBackend { pub threads: Vec>, queues_per_thread: Vec, pub exit_event: EventFd, + pub handler_thread: Mutex>>, } impl VhostUserVsockBackend { @@ -279,6 +285,7 @@ impl VhostUserVsockBackend { threads: vec![thread], queues_per_thread, exit_event: EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?, + handler_thread: Mutex::new(None), }) } } @@ -303,7 +310,62 @@ impl VhostUserBackend for VhostUserVsockBackend { } fn protocol_features(&self) -> VhostUserProtocolFeatures { - VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIG + VhostUserProtocolFeatures::MQ + | VhostUserProtocolFeatures::CONFIG + | VhostUserProtocolFeatures::DEVICE_STATE + } + + #[allow(unused_variables)] + fn set_device_state_fd( + &self, + direction: VhostTransferStateDirection, + phase: VhostTransferStatePhase, + file: File, + ) -> IoResult> { + let handle = thread::spawn(move || { + match direction { + VhostTransferStateDirection::SAVE => { + // save + // No device state to save yet, just close the FD. + drop(file); + } + VhostTransferStateDirection::LOAD => { + // load + // No device state to load yet, just verify it is empty. + let mut data = Vec::new(); + let mut reader = BufReader::new(file); + if reader.read_to_end(&mut data).is_err() { + println!("vhost-device-vsock loaded device state read failed"); + return; + } + + if data.len() > 0 { + println!("vhost-device-vsock loaded device state is non-empty. BUG!"); + return; + } + } + _ => { + println!("invalid transfer_direction"); + return; + } + } + }); + *self.handler_thread.lock().unwrap() = Some(handle); + Ok(None) + } + + fn check_device_state(&self) -> IoResult<()> { + if !self.handler_thread.lock().unwrap().is_none() { + self.handler_thread + .lock() + .unwrap() + .take() + .unwrap() + .join() + .unwrap(); + *self.handler_thread.lock().unwrap() = None; + } + Ok(()) } fn set_event_idx(&self, enabled: bool) { diff --git a/vhost-device-vsock/src/vhu_vsock_thread.rs b/vhost-device-vsock/src/vhu_vsock_thread.rs index 2cd9c4db..f56b65d4 100644 --- a/vhost-device-vsock/src/vhu_vsock_thread.rs +++ b/vhost-device-vsock/src/vhu_vsock_thread.rs @@ -586,6 +586,10 @@ impl VhostUserVsockThread { let mut vring_mut = vring.get_mut(); + if !vring_mut.get_enabled() { + return Ok(()); + } + let queue = vring_mut.get_queue_mut(); while let Some(mut avail_desc) = queue @@ -657,6 +661,8 @@ impl VhostUserVsockThread { loop { if !self.thread_backend.pending_rx() { break; + } else if !vring.get_enabled() { + break; } vring.disable_notification().unwrap(); @@ -677,6 +683,8 @@ impl VhostUserVsockThread { loop { if !self.thread_backend.pending_raw_pkts() { break; + } else if !vring.get_enabled() { + break; } vring.disable_notification().unwrap(); @@ -722,8 +730,12 @@ impl VhostUserVsockThread { None => return Err(Error::NoMemoryConfigured), }; - while let Some(mut avail_desc) = vring - .get_mut() + let mut vring_mut = vring.get_mut(); + if !vring_mut.get_enabled() { + return Ok(()); + } + + while let Some(mut avail_desc) = vring_mut .get_queue_mut() .iter(atomic_mem.memory()) .map_err(|_| Error::IterateQueue)?