mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-21 07:21:15 +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),
|
VhostUserNetSetup(vhost_user::Error),
|
||||||
/// Failed to setup vhost-user daemon.
|
/// Failed to setup vhost-user daemon.
|
||||||
VhostUserBlkSetup(vhost_user::Error),
|
VhostUserBlkSetup(vhost_user::Error),
|
||||||
|
/// Failed to reset vhost-user daemon.
|
||||||
|
VhostUserReset(vhost_user::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ActivateResult = std::result::Result<(), ActivateError>;
|
pub type ActivateResult = std::result::Result<(), ActivateError>;
|
||||||
|
@ -37,11 +37,13 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {}
|
|||||||
|
|
||||||
pub struct Blk {
|
pub struct Blk {
|
||||||
vhost_user_blk: Master,
|
vhost_user_blk: Master,
|
||||||
kill_evt: EventFd,
|
kill_evt: Option<EventFd>,
|
||||||
avail_features: u64,
|
avail_features: u64,
|
||||||
acked_features: u64,
|
acked_features: u64,
|
||||||
config_space: Vec<u8>,
|
config_space: Vec<u8>,
|
||||||
queue_sizes: Vec<u16>,
|
queue_sizes: Vec<u16>,
|
||||||
|
queue_evts: Option<Vec<EventFd>>,
|
||||||
|
interrupt_cb: Option<Arc<VirtioInterrupt>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Blk {
|
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)
|
let mut vhost_user_blk = Master::connect(vu_cfg.sock, vu_cfg.num_queues as u64)
|
||||||
.map_err(Error::VhostUserCreateMaster)?;
|
.map_err(Error::VhostUserCreateMaster)?;
|
||||||
|
|
||||||
let kill_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?;
|
|
||||||
|
|
||||||
// Filling device and vring features VMM supports.
|
// Filling device and vring features VMM supports.
|
||||||
let mut avail_features = 1 << VIRTIO_BLK_F_SEG_MAX
|
let mut avail_features = 1 << VIRTIO_BLK_F_SEG_MAX
|
||||||
| 1 << VIRTIO_BLK_F_RO
|
| 1 << VIRTIO_BLK_F_RO
|
||||||
@ -117,19 +117,23 @@ impl<'a> Blk {
|
|||||||
|
|
||||||
Ok(Blk {
|
Ok(Blk {
|
||||||
vhost_user_blk,
|
vhost_user_blk,
|
||||||
kill_evt,
|
kill_evt: None,
|
||||||
avail_features,
|
avail_features,
|
||||||
acked_features,
|
acked_features,
|
||||||
config_space,
|
config_space,
|
||||||
queue_sizes: vec![vu_cfg.queue_size; vu_cfg.num_queues],
|
queue_sizes: vec![vu_cfg.queue_size; vu_cfg.num_queues],
|
||||||
|
queue_evts: None,
|
||||||
|
interrupt_cb: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Blk {
|
impl Drop for Blk {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Err(_e) = self.kill_evt.write(1) {
|
if let Some(kill_evt) = self.kill_evt.take() {
|
||||||
error!("failed to kill vhost-user-blk with error {}", _e);
|
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>,
|
queues: Vec<Queue>,
|
||||||
queue_evts: Vec<EventFd>,
|
queue_evts: Vec<EventFd>,
|
||||||
) -> ActivateResult {
|
) -> ActivateResult {
|
||||||
let handler_kill_evt = self
|
let (self_kill_evt, kill_evt) =
|
||||||
.kill_evt
|
match EventFd::new(EFD_NONBLOCK).and_then(|e| Ok((e.try_clone()?, e))) {
|
||||||
.try_clone()
|
Ok(v) => v,
|
||||||
.map_err(|_| ActivateError::CloneKillEventFd)?;
|
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(
|
let vu_interrupt_list = setup_vhost_user(
|
||||||
&mut self.vhost_user_blk,
|
&mut self.vhost_user_blk,
|
||||||
@ -228,7 +252,7 @@ impl VirtioDevice for Blk {
|
|||||||
|
|
||||||
let mut handler = VhostUserEpollHandler::<SlaveReqHandler>::new(VhostUserEpollConfig {
|
let mut handler = VhostUserEpollHandler::<SlaveReqHandler>::new(VhostUserEpollConfig {
|
||||||
interrupt_cb,
|
interrupt_cb,
|
||||||
kill_evt: handler_kill_evt,
|
kill_evt,
|
||||||
vu_interrupt_list,
|
vu_interrupt_list,
|
||||||
slave_req_handler: None,
|
slave_req_handler: None,
|
||||||
});
|
});
|
||||||
@ -245,4 +269,22 @@ impl VirtioDevice for Blk {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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,
|
VhostUserProtocolNotSupport,
|
||||||
/// Set owner failed.
|
/// Set owner failed.
|
||||||
VhostUserSetOwner(VhostError),
|
VhostUserSetOwner(VhostError),
|
||||||
|
/// Reset owner failed.
|
||||||
|
VhostUserResetOwner(VhostError),
|
||||||
/// Set features failed.
|
/// Set features failed.
|
||||||
VhostUserSetFeatures(VhostError),
|
VhostUserSetFeatures(VhostError),
|
||||||
/// Set protocol features failed.
|
/// Set protocol features failed.
|
||||||
|
@ -106,3 +106,18 @@ pub fn setup_vhost_user(
|
|||||||
|
|
||||||
setup_vhost_user_vring(vu, mem, queues, queue_evts)
|
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…
Reference in New Issue
Block a user