vmm: Shutdown VMM if API thread panics

See: #3031

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-09-10 10:21:23 +01:00 committed by Bo Chen
parent 171d12943d
commit b6b686c71c
2 changed files with 73 additions and 40 deletions

View File

@ -14,6 +14,7 @@ use std::collections::HashMap;
use std::fs::File;
use std::os::unix::io::{IntoRawFd, RawFd};
use std::os::unix::net::UnixListener;
use std::panic::AssertUnwindSafe;
use std::path::PathBuf;
use std::sync::mpsc::Sender;
use std::sync::Arc;
@ -267,6 +268,7 @@ fn start_http_thread(
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
seccomp_action: &SeccompAction,
exit_evt: EventFd,
) -> Result<thread::JoinHandle<Result<()>>> {
// Retrieve seccomp filter for API thread
let api_seccomp_filter =
@ -277,32 +279,44 @@ fn start_http_thread(
.spawn(move || {
// Apply seccomp filter for API thread.
if !api_seccomp_filter.is_empty() {
apply_filter(&api_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
apply_filter(&api_seccomp_filter)
.map_err(Error::ApplySeccompFilter)
.map_err(|e| {
error!("Error applying seccomp filter: {:?}", e);
exit_evt.write(1).ok();
e
})?;
}
server.start_server().unwrap();
loop {
match server.requests() {
Ok(request_vec) => {
for server_request in request_vec {
server
.respond(server_request.process(|request| {
std::panic::catch_unwind(AssertUnwindSafe(move || {
server.start_server().unwrap();
loop {
match server.requests() {
Ok(request_vec) => {
for server_request in request_vec {
if let Err(e) = server.respond(server_request.process(|request| {
handle_http_request(request, &api_notifier, &api_sender)
}))
.or_else(|e| {
})) {
error!("HTTP server error on response: {}", e);
Ok(())
})?;
}
}
}
Err(e) => {
error!(
"HTTP server error on retrieving incoming request. Error: {}",
e
);
}
}
Err(e) => {
error!(
"HTTP server error on retrieving incoming request. Error: {}",
e
);
}
}
}
}))
.map_err(|_| {
error!("http-server thread panicked");
exit_evt.write(1).ok()
})
.ok();
Ok(())
})
.map_err(Error::HttpThreadSpawn)
}
@ -312,13 +326,14 @@ pub fn start_http_path_thread(
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
seccomp_action: &SeccompAction,
exit_evt: EventFd,
) -> Result<thread::JoinHandle<Result<()>>> {
std::fs::remove_file(path).unwrap_or_default();
let socket_path = PathBuf::from(path);
let socket_fd = UnixListener::bind(socket_path).map_err(Error::CreateApiServerSocket)?;
let server =
HttpServer::new_from_fd(socket_fd.into_raw_fd()).map_err(Error::CreateApiServer)?;
start_http_thread(server, api_notifier, api_sender, seccomp_action)
start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt)
}
pub fn start_http_fd_thread(
@ -326,7 +341,8 @@ pub fn start_http_fd_thread(
api_notifier: EventFd,
api_sender: Sender<ApiRequest>,
seccomp_action: &SeccompAction,
exit_evt: EventFd,
) -> Result<thread::JoinHandle<Result<()>>> {
let server = HttpServer::new_from_fd(fd).map_err(Error::CreateApiServer)?;
start_http_thread(server, api_notifier, api_sender, seccomp_action)
start_http_thread(server, api_notifier, api_sender, seccomp_action, exit_evt)
}

View File

@ -262,30 +262,47 @@ pub fn start_vmm_thread(
get_seccomp_filter(seccomp_action, Thread::Vmm).map_err(Error::CreateSeccompFilter)?;
let vmm_seccomp_action = seccomp_action.clone();
let thread = thread::Builder::new()
.name("vmm".to_string())
.spawn(move || {
// Apply seccomp filter for VMM thread.
if !vmm_seccomp_filter.is_empty() {
apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
}
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
let thread = {
let exit_evt = exit_evt.try_clone().map_err(Error::EventFdClone)?;
thread::Builder::new()
.name("vmm".to_string())
.spawn(move || {
// Apply seccomp filter for VMM thread.
if !vmm_seccomp_filter.is_empty() {
apply_filter(&vmm_seccomp_filter).map_err(Error::ApplySeccompFilter)?;
}
let mut vmm = Vmm::new(
vmm_version.to_string(),
api_event,
vmm_seccomp_action,
hypervisor,
)?;
let mut vmm = Vmm::new(
vmm_version.to_string(),
api_event,
vmm_seccomp_action,
hypervisor,
exit_evt,
)?;
vmm.control_loop(Arc::new(api_receiver))
})
.map_err(Error::VmmThreadSpawn)?;
vmm.control_loop(Arc::new(api_receiver))
})
.map_err(Error::VmmThreadSpawn)?
};
// The VMM thread is started, we can start serving HTTP requests
if let Some(http_path) = http_path {
api::start_http_path_thread(http_path, http_api_event, api_sender, seccomp_action)?;
api::start_http_path_thread(
http_path,
http_api_event,
api_sender,
seccomp_action,
exit_evt,
)?;
} else if let Some(http_fd) = http_fd {
api::start_http_fd_thread(http_fd, http_api_event, api_sender, seccomp_action)?;
api::start_http_fd_thread(
http_fd,
http_api_event,
api_sender,
seccomp_action,
exit_evt,
)?;
}
Ok(thread)
}
@ -316,9 +333,9 @@ impl Vmm {
api_evt: EventFd,
seccomp_action: SeccompAction,
hypervisor: Arc<dyn hypervisor::Hypervisor>,
exit_evt: EventFd,
) -> Result<Self> {
let mut epoll = EpollContext::new().map_err(Error::Epoll)?;
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
let activate_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;