vhost_user_block: Implement and use worker shutdown

Add a kill EventFD and use this to shutdown the worker thread when the
backend terminates.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-02-07 10:38:02 +00:00 committed by Sebastien Boeuf
parent e619fe6b01
commit 7ca691fc2f

View File

@ -14,6 +14,7 @@ extern crate vhost_user_backend;
extern crate vm_virtio; extern crate vm_virtio;
use epoll; use epoll;
use libc::EFD_NONBLOCK;
use log::*; use log::*;
use qcow::{self, ImageType, QcowFile}; use qcow::{self, ImageType, QcowFile};
use std::fs::File; use std::fs::File;
@ -21,7 +22,7 @@ use std::fs::OpenOptions;
use std::io::Read; use std::io::Read;
use std::io::{Seek, SeekFrom, Write}; use std::io::{Seek, SeekFrom, Write};
use std::mem; use std::mem;
use std::os::unix::fs::OpenOptionsExt; use std::os::unix::{fs::OpenOptionsExt, io::AsRawFd};
use std::path::PathBuf; use std::path::PathBuf;
use std::process; use std::process;
use std::slice; use std::slice;
@ -33,6 +34,7 @@ use vhost_user_backend::{VhostUserBackend, VhostUserDaemon, Vring, VringWorker};
use virtio_bindings::bindings::virtio_blk::*; use virtio_bindings::bindings::virtio_blk::*;
use vm_memory::{Bytes, GuestMemoryError, GuestMemoryMmap}; use vm_memory::{Bytes, GuestMemoryError, GuestMemoryMmap};
use vm_virtio::block::{build_disk_image_id, Request}; use vm_virtio::block::{build_disk_image_id, Request};
use vmm_sys_util::eventfd::EventFd;
const QUEUE_SIZE: usize = 1024; const QUEUE_SIZE: usize = 1024;
const SECTOR_SHIFT: u8 = 9; const SECTOR_SHIFT: u8 = 9;
@ -65,6 +67,10 @@ pub enum Error {
ParseBlkNumQueuesParam(std::num::ParseIntError), ParseBlkNumQueuesParam(std::num::ParseIntError),
/// Failed to handle event other than input event. /// Failed to handle event other than input event.
HandleEventNotEpollIn, HandleEventNotEpollIn,
/// Failed to create kill eventfd
CreateKillEventFd(io::Error),
/// Failed to handle unknown event.
HandleEventUnknownEvent,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -89,6 +95,7 @@ pub struct VhostUserBlkBackend {
disk_nsectors: u64, disk_nsectors: u64,
config: virtio_blk_config, config: virtio_blk_config,
rdonly: bool, rdonly: bool,
kill_evt: EventFd,
} }
impl VhostUserBlkBackend { impl VhostUserBlkBackend {
@ -129,6 +136,7 @@ impl VhostUserBlkBackend {
disk_nsectors: nsectors, disk_nsectors: nsectors,
config, config,
rdonly, rdonly,
kill_evt: EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?,
}) })
} }
@ -177,6 +185,13 @@ impl VhostUserBlkBackend {
pub fn set_vring_worker(&mut self, vring_worker: Option<Arc<VringWorker>>) { pub fn set_vring_worker(&mut self, vring_worker: Option<Arc<VringWorker>>) {
self.vring_worker = vring_worker; self.vring_worker = vring_worker;
} }
pub fn get_kill_event(&self) -> (u16, EventFd) {
(
self.config.num_queues as u16,
self.kill_evt.try_clone().unwrap(),
)
}
} }
impl VhostUserBackend for VhostUserBlkBackend { impl VhostUserBackend for VhostUserBlkBackend {
@ -221,14 +236,21 @@ impl VhostUserBackend for VhostUserBlkBackend {
debug!("event received: {:?}", device_event); debug!("event received: {:?}", device_event);
let mut vring = vrings[device_event as usize].write().unwrap(); // Kill event is the index after the last queue
let kill_index = self.config.num_queues;
match device_event {
event if event == kill_index => Ok(true),
q if device_event < self.config.num_queues => {
let mut vring = vrings[q as usize].write().unwrap();
if self.process_queue(&mut vring) { if self.process_queue(&mut vring) {
debug!("signalling queue"); debug!("signalling queue");
vring.signal_used_queue().unwrap(); vring.signal_used_queue().unwrap();
} }
Ok(false) Ok(false)
} }
_ => Err(Error::HandleEventUnknownEvent.into()),
}
}
fn get_config(&self, _offset: u32, _size: u32) -> Vec<u8> { fn get_config(&self, _offset: u32, _size: u32) -> Vec<u8> {
// self.config is a statically allocated virtio_blk_config // self.config is a statically allocated virtio_blk_config
@ -334,6 +356,15 @@ pub fn start_block_backend(backend_command: &str) {
debug!("blk_daemon is created!\n"); debug!("blk_daemon is created!\n");
let vring_worker = blk_daemon.get_vring_worker(); let vring_worker = blk_daemon.get_vring_worker();
let (kill_index, kill_evt_fd) = blk_backend.read().unwrap().get_kill_event();
if let Err(e) = vring_worker.register_listener(
kill_evt_fd.as_raw_fd(),
epoll::Events::EPOLLIN,
u64::from(kill_index),
) {
error!("Failed to register listener for kill event: {:?}", e);
process::exit(1);
}
blk_backend blk_backend
.write() .write()
@ -341,12 +372,18 @@ pub fn start_block_backend(backend_command: &str) {
.set_vring_worker(Some(vring_worker)); .set_vring_worker(Some(vring_worker));
if let Err(e) = blk_daemon.start() { if let Err(e) = blk_daemon.start() {
println!( error!(
"failed to start daemon for vhost-user-blk with error: {:?}\n", "Failed to start daemon for vhost-user-block with error: {:?}\n",
e e
); );
process::exit(1); process::exit(1);
} }
blk_daemon.wait().unwrap(); if let Err(e) = blk_daemon.wait() {
error!("Error from the main thread: {:?}", e);
}
if let Err(e) = kill_evt_fd.write(1) {
error!("Error shutting down worker thread: {:?}", e)
}
} }