mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 03:12:27 +00:00
vm-virtio: vhost-user-blk: Add support for reset
If we expect the vhost-user-blk device to be used for booting a VMM along with the firmware, then need the device to support being reset. In the vhost-user context, this means the backend needs to be informed the vrings are disabled and stopped, and the owner needs to be reset too. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
0a229ef4f5
commit
d723b7dae8
@ -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>;
|
||||
|
@ -37,11 +37,13 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {}
|
||||
|
||||
pub struct Blk {
|
||||
vhost_user_blk: Master,
|
||||
kill_evt: EventFd,
|
||||
kill_evt: Option<EventFd>,
|
||||
avail_features: u64,
|
||||
acked_features: u64,
|
||||
config_space: Vec<u8>,
|
||||
queue_sizes: Vec<u16>,
|
||||
queue_evts: Option<Vec<EventFd>>,
|
||||
interrupt_cb: Option<Arc<VirtioInterrupt>>,
|
||||
}
|
||||
|
||||
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>,
|
||||
queue_evts: Vec<EventFd>,
|
||||
) -> 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<EventFd> = 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::<SlaveReqHandler>::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<VirtioInterrupt>, Vec<EventFd>)> {
|
||||
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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user