mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-13 23:22:07 +00:00
main: reset tty if starting the VM fails
When I refactored this to centralise resetting the tty into DeviceManager::drop, I tested that the tty was reset if an error happened on the vmm thread, but not on the main thread. It turns out that if an error happened on the main thread, the process would just exit, so drop handlers on other threads wouldn't get run. To fix this, I've changed start_vmm() to write to the VMM's exit eventfd and then join the thread if an error happens after the vmm thread is started. Fixes: b6feae0a ("vmm: only touch the tty flags if it's being used") Signed-off-by: Alyssa Ross <hi@alyssa.is>
This commit is contained in:
parent
cc1254d5e1
commit
5492259af9
21
src/main.rs
21
src/main.rs
@ -8,7 +8,7 @@ extern crate event_monitor;
|
|||||||
|
|
||||||
use argh::FromArgs;
|
use argh::FromArgs;
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
use log::LevelFilter;
|
use log::{warn, LevelFilter};
|
||||||
use option_parser::OptionParser;
|
use option_parser::OptionParser;
|
||||||
use seccompiler::SeccompAction;
|
use seccompiler::SeccompAction;
|
||||||
use signal_hook::consts::SIGSYS;
|
use signal_hook::consts::SIGSYS;
|
||||||
@ -33,6 +33,8 @@ enum Error {
|
|||||||
#[cfg(feature = "guest_debug")]
|
#[cfg(feature = "guest_debug")]
|
||||||
#[error("Failed to create Debug EventFd: {0}")]
|
#[error("Failed to create Debug EventFd: {0}")]
|
||||||
CreateDebugEventFd(#[source] std::io::Error),
|
CreateDebugEventFd(#[source] std::io::Error),
|
||||||
|
#[error("Failed to create exit EventFd: {0}")]
|
||||||
|
CreateExitEventFd(#[source] std::io::Error),
|
||||||
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
|
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
|
||||||
CreateHypervisor(#[source] hypervisor::HypervisorError),
|
CreateHypervisor(#[source] hypervisor::HypervisorError),
|
||||||
#[error("Failed to start the VMM thread: {0}")]
|
#[error("Failed to start the VMM thread: {0}")]
|
||||||
@ -509,6 +511,8 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
|||||||
#[cfg(feature = "guest_debug")]
|
#[cfg(feature = "guest_debug")]
|
||||||
let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
|
let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
|
||||||
|
|
||||||
|
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
|
||||||
|
|
||||||
let vmm_thread = vmm::start_vmm_thread(
|
let vmm_thread = vmm::start_vmm_thread(
|
||||||
env!("CARGO_PKG_VERSION").to_string(),
|
env!("CARGO_PKG_VERSION").to_string(),
|
||||||
&api_socket_path,
|
&api_socket_path,
|
||||||
@ -522,11 +526,13 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
|||||||
debug_evt.try_clone().unwrap(),
|
debug_evt.try_clone().unwrap(),
|
||||||
#[cfg(feature = "guest_debug")]
|
#[cfg(feature = "guest_debug")]
|
||||||
vm_debug_evt.try_clone().unwrap(),
|
vm_debug_evt.try_clone().unwrap(),
|
||||||
|
exit_evt.try_clone().unwrap(),
|
||||||
&seccomp_action,
|
&seccomp_action,
|
||||||
hypervisor,
|
hypervisor,
|
||||||
)
|
)
|
||||||
.map_err(Error::StartVmmThread)?;
|
.map_err(Error::StartVmmThread)?;
|
||||||
|
|
||||||
|
let r: Result<(), Error> = (|| {
|
||||||
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
|
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
|
||||||
|
|
||||||
if payload_present {
|
if payload_present {
|
||||||
@ -546,11 +552,22 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
|||||||
vmm::api::vm_restore(
|
vmm::api::vm_restore(
|
||||||
api_evt.try_clone().unwrap(),
|
api_evt.try_clone().unwrap(),
|
||||||
api_request_sender,
|
api_request_sender,
|
||||||
Arc::new(config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?),
|
Arc::new(
|
||||||
|
config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.map_err(Error::VmRestore)?;
|
.map_err(Error::VmRestore)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})();
|
||||||
|
|
||||||
|
if r.is_err() {
|
||||||
|
if let Err(e) = exit_evt.write(1) {
|
||||||
|
warn!("writing to exit EventFd: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vmm_thread
|
vmm_thread
|
||||||
.join()
|
.join()
|
||||||
.map_err(Error::ThreadJoin)?
|
.map_err(Error::ThreadJoin)?
|
||||||
|
@ -289,6 +289,7 @@ pub fn start_vmm_thread(
|
|||||||
#[cfg(feature = "guest_debug")] debug_path: Option<PathBuf>,
|
#[cfg(feature = "guest_debug")] debug_path: Option<PathBuf>,
|
||||||
#[cfg(feature = "guest_debug")] debug_event: EventFd,
|
#[cfg(feature = "guest_debug")] debug_event: EventFd,
|
||||||
#[cfg(feature = "guest_debug")] vm_debug_event: EventFd,
|
#[cfg(feature = "guest_debug")] vm_debug_event: EventFd,
|
||||||
|
exit_event: EventFd,
|
||||||
seccomp_action: &SeccompAction,
|
seccomp_action: &SeccompAction,
|
||||||
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
hypervisor: Arc<dyn hypervisor::Hypervisor>,
|
||||||
) -> Result<thread::JoinHandle<Result<()>>> {
|
) -> Result<thread::JoinHandle<Result<()>>> {
|
||||||
@ -309,9 +310,8 @@ pub fn start_vmm_thread(
|
|||||||
.map_err(Error::CreateSeccompFilter)?;
|
.map_err(Error::CreateSeccompFilter)?;
|
||||||
|
|
||||||
let vmm_seccomp_action = seccomp_action.clone();
|
let vmm_seccomp_action = seccomp_action.clone();
|
||||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
|
||||||
let thread = {
|
let thread = {
|
||||||
let exit_evt = exit_evt.try_clone().map_err(Error::EventFdClone)?;
|
let exit_event = exit_event.try_clone().map_err(Error::EventFdClone)?;
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("vmm".to_string())
|
.name("vmm".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
@ -329,7 +329,7 @@ pub fn start_vmm_thread(
|
|||||||
vm_debug_event,
|
vm_debug_event,
|
||||||
vmm_seccomp_action,
|
vmm_seccomp_action,
|
||||||
hypervisor,
|
hypervisor,
|
||||||
exit_evt,
|
exit_event,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
vmm.setup_signal_handler()?;
|
vmm.setup_signal_handler()?;
|
||||||
@ -350,7 +350,7 @@ pub fn start_vmm_thread(
|
|||||||
http_api_event,
|
http_api_event,
|
||||||
api_sender,
|
api_sender,
|
||||||
seccomp_action,
|
seccomp_action,
|
||||||
exit_evt,
|
exit_event,
|
||||||
hypervisor_type,
|
hypervisor_type,
|
||||||
)?;
|
)?;
|
||||||
} else if let Some(http_fd) = http_fd {
|
} else if let Some(http_fd) = http_fd {
|
||||||
@ -359,7 +359,7 @@ pub fn start_vmm_thread(
|
|||||||
http_api_event,
|
http_api_event,
|
||||||
api_sender,
|
api_sender,
|
||||||
seccomp_action,
|
seccomp_action,
|
||||||
exit_evt,
|
exit_event,
|
||||||
hypervisor_type,
|
hypervisor_type,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -314,10 +314,10 @@ impl VmState {
|
|||||||
fn valid_transition(self, new_state: VmState) -> Result<()> {
|
fn valid_transition(self, new_state: VmState) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
VmState::Created => match new_state {
|
VmState::Created => match new_state {
|
||||||
VmState::Created | VmState::Shutdown => {
|
VmState::Created => Err(Error::InvalidStateTransition(self, new_state)),
|
||||||
Err(Error::InvalidStateTransition(self, new_state))
|
VmState::Running | VmState::Paused | VmState::BreakPoint | VmState::Shutdown => {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
VmState::Running | VmState::Paused | VmState::BreakPoint => Ok(()),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
VmState::Running => match new_state {
|
VmState::Running => match new_state {
|
||||||
@ -2694,7 +2694,7 @@ mod tests {
|
|||||||
// Check the transitions from Created
|
// Check the transitions from Created
|
||||||
assert!(state.valid_transition(VmState::Created).is_err());
|
assert!(state.valid_transition(VmState::Created).is_err());
|
||||||
assert!(state.valid_transition(VmState::Running).is_ok());
|
assert!(state.valid_transition(VmState::Running).is_ok());
|
||||||
assert!(state.valid_transition(VmState::Shutdown).is_err());
|
assert!(state.valid_transition(VmState::Shutdown).is_ok());
|
||||||
assert!(state.valid_transition(VmState::Paused).is_ok());
|
assert!(state.valid_transition(VmState::Paused).is_ok());
|
||||||
assert!(state.valid_transition(VmState::BreakPoint).is_ok());
|
assert!(state.valid_transition(VmState::BreakPoint).is_ok());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user