diff --git a/vm-virtio/src/lib.rs b/vm-virtio/src/lib.rs index d6ce1f348..46c975290 100755 --- a/vm-virtio/src/lib.rs +++ b/vm-virtio/src/lib.rs @@ -132,6 +132,8 @@ pub enum ActivateError { VhostUserNetSetup(vhost_user::Error), /// Failed to setup vhost-user daemon. VhostUserBlkSetup(vhost_user::Error), + /// Failed to reset vhost-user daemon. + VhostUserReset(vhost_user::Error), } pub type ActivateResult = std::result::Result<(), ActivateError>; diff --git a/vm-virtio/src/vhost_user/blk.rs b/vm-virtio/src/vhost_user/blk.rs index f2d846526..ed6abc008 100644 --- a/vm-virtio/src/vhost_user/blk.rs +++ b/vm-virtio/src/vhost_user/blk.rs @@ -37,11 +37,13 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {} pub struct Blk { vhost_user_blk: Master, - kill_evt: EventFd, + kill_evt: Option, avail_features: u64, acked_features: u64, config_space: Vec, queue_sizes: Vec, + queue_evts: Option>, + interrupt_cb: Option>, } impl<'a> Blk { @@ -50,8 +52,6 @@ impl<'a> Blk { let mut vhost_user_blk = Master::connect(vu_cfg.sock, vu_cfg.num_queues as u64) .map_err(Error::VhostUserCreateMaster)?; - let kill_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?; - // Filling device and vring features VMM supports. let mut avail_features = 1 << VIRTIO_BLK_F_SEG_MAX | 1 << VIRTIO_BLK_F_RO @@ -117,19 +117,23 @@ impl<'a> Blk { Ok(Blk { vhost_user_blk, - kill_evt, + kill_evt: None, avail_features, acked_features, config_space, queue_sizes: vec![vu_cfg.queue_size; vu_cfg.num_queues], + queue_evts: None, + interrupt_cb: None, }) } } impl Drop for Blk { fn drop(&mut self) { - if let Err(_e) = self.kill_evt.write(1) { - error!("failed to kill vhost-user-blk with error {}", _e); + if let Some(kill_evt) = self.kill_evt.take() { + if let Err(e) = kill_evt.write(1) { + error!("failed to kill vhost-user-blk: {:?}", e); + } } } } @@ -212,10 +216,30 @@ impl VirtioDevice for Blk { queues: Vec, queue_evts: Vec, ) -> ActivateResult { - let handler_kill_evt = self - .kill_evt - .try_clone() - .map_err(|_| ActivateError::CloneKillEventFd)?; + let (self_kill_evt, kill_evt) = + match EventFd::new(EFD_NONBLOCK).and_then(|e| Ok((e.try_clone()?, e))) { + Ok(v) => v, + Err(e) => { + error!("failed creating kill EventFd pair: {}", e); + return Err(ActivateError::BadActivate); + } + }; + self.kill_evt = Some(self_kill_evt); + + // Save the interrupt EventFD as we need to return it on reset + // but clone it to pass into the thread. + self.interrupt_cb = Some(interrupt_cb.clone()); + + let mut tmp_queue_evts: Vec = Vec::new(); + for queue_evt in queue_evts.iter() { + // Save the queue EventFD as we need to return it on reset + // but clone it to pass into the thread. + tmp_queue_evts.push(queue_evt.try_clone().map_err(|e| { + error!("failed to clone queue EventFd: {}", e); + ActivateError::BadActivate + })?); + } + self.queue_evts = Some(tmp_queue_evts); let vu_interrupt_list = setup_vhost_user( &mut self.vhost_user_blk, @@ -228,7 +252,7 @@ impl VirtioDevice for Blk { let mut handler = VhostUserEpollHandler::::new(VhostUserEpollConfig { interrupt_cb, - kill_evt: handler_kill_evt, + kill_evt, vu_interrupt_list, slave_req_handler: None, }); @@ -245,4 +269,22 @@ impl VirtioDevice for Blk { } Ok(()) } + + fn reset(&mut self) -> Option<(Arc, Vec)> { + if let Err(e) = reset_vhost_user(&mut self.vhost_user_blk, self.queue_sizes.len()) { + error!("Failed to reset vhost-user daemon: {:?}", e); + return None; + } + + if let Some(kill_evt) = self.kill_evt.take() { + // Ignore the result because there is nothing we can do about it. + let _ = kill_evt.write(1); + } + + // Return the interrupt and queue EventFDs + Some(( + self.interrupt_cb.take().unwrap(), + self.queue_evts.take().unwrap(), + )) + } } diff --git a/vm-virtio/src/vhost_user/mod.rs b/vm-virtio/src/vhost_user/mod.rs index 26fce84e3..08157a00f 100644 --- a/vm-virtio/src/vhost_user/mod.rs +++ b/vm-virtio/src/vhost_user/mod.rs @@ -61,6 +61,8 @@ pub enum Error { VhostUserProtocolNotSupport, /// Set owner failed. VhostUserSetOwner(VhostError), + /// Reset owner failed. + VhostUserResetOwner(VhostError), /// Set features failed. VhostUserSetFeatures(VhostError), /// Set protocol features failed. diff --git a/vm-virtio/src/vhost_user/vu_common_ctrl.rs b/vm-virtio/src/vhost_user/vu_common_ctrl.rs index 670f8e6f2..01e84f4d3 100644 --- a/vm-virtio/src/vhost_user/vu_common_ctrl.rs +++ b/vm-virtio/src/vhost_user/vu_common_ctrl.rs @@ -106,3 +106,18 @@ pub fn setup_vhost_user( setup_vhost_user_vring(vu, mem, queues, queue_evts) } + +pub fn reset_vhost_user(vu: &mut Master, num_queues: usize) -> Result<()> { + for queue_index in 0..num_queues { + // Disable the vrings. + vu.set_vring_enable(queue_index, false) + .map_err(Error::VhostUserSetVringEnable)?; + + // Stop the vrings. + vu.get_vring_base(queue_index) + .map_err(Error::VhostUserSetFeatures)?; + } + + // Reset the owner. + vu.reset_owner().map_err(Error::VhostUserResetOwner) +}