From 8b585b96c1d39a9f065314b3903a407e5a9dd8b2 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Tue, 10 May 2022 19:21:02 +0800 Subject: [PATCH] vmm: enable coredump Based on the newly added guest_debug feature, this patch adds http endpoint support. Signed-off-by: Yi Wang Co-authored-by: Sebastien Boeuf --- Cargo.toml | 1 + vmm/src/api/http.rs | 2 ++ vmm/src/api/http_endpoint.rs | 8 ++++++++ vmm/src/api/mod.rs | 28 ++++++++++++++++++++++++++++ vmm/src/coredump.rs | 1 - vmm/src/lib.rs | 20 ++++++++++++++++++++ 6 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8dbdfee99..e92d66b4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ amx = ["vmm/amx"] cmos = ["vmm/cmos"] fwdebug = ["vmm/fwdebug"] gdb = ["vmm/gdb"] +guest_debug = ["vmm/guest_debug"] kvm = ["vmm/kvm"] mshv = ["vmm/mshv"] tdx = ["vmm/tdx"] diff --git a/vmm/src/api/http.rs b/vmm/src/api/http.rs index 6a643d2d0..17a520657 100644 --- a/vmm/src/api/http.rs +++ b/vmm/src/api/http.rs @@ -161,6 +161,8 @@ lazy_static! { r.routes.insert(endpoint!("/vm.send-migration"), Box::new(VmActionHandler::new(VmAction::SendMigration(Arc::default())))); r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown))); r.routes.insert(endpoint!("/vm.snapshot"), Box::new(VmActionHandler::new(VmAction::Snapshot(Arc::default())))); + #[cfg(feature = "guest_debug")] + r.routes.insert(endpoint!("/vm.coredump"), Box::new(VmActionHandler::new(VmAction::Coredump(Arc::default())))); r.routes.insert(endpoint!("/vmm.ping"), Box::new(VmmPing {})); r.routes.insert(endpoint!("/vmm.shutdown"), Box::new(VmmShutdown {})); diff --git a/vmm/src/api/http_endpoint.rs b/vmm/src/api/http_endpoint.rs index 7e3afdc1d..2034712aa 100644 --- a/vmm/src/api/http_endpoint.rs +++ b/vmm/src/api/http_endpoint.rs @@ -4,6 +4,8 @@ // use crate::api::http::{error_response, EndpointHandler, HttpError}; +#[cfg(feature = "guest_debug")] +use crate::api::vm_coredump; use crate::api::{ vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_user_device, vm_add_vdpa, vm_add_vsock, vm_boot, vm_counters, vm_create, vm_delete, vm_info, vm_pause, @@ -151,6 +153,12 @@ impl EndpointHandler for VmActionHandler { api_sender, Arc::new(serde_json::from_slice(body.raw())?), ), + #[cfg(feature = "guest_debug")] + Coredump(_) => vm_coredump( + api_notifier, + api_sender, + Arc::new(serde_json::from_slice(body.raw())?), + ), ReceiveMigration(_) => vm_receive_migration( api_notifier, api_sender, diff --git a/vmm/src/api/mod.rs b/vmm/src/api/mod.rs index 36c457ea9..0513ef371 100644 --- a/vmm/src/api/mod.rs +++ b/vmm/src/api/mod.rs @@ -99,6 +99,9 @@ pub enum ApiError { /// The VM could not restored. VmRestore(VmError), + /// The VM could not be coredumped. + VmCoredump(VmError), + /// The VMM could not shutdown. VmmShutdown(VmError), @@ -189,6 +192,12 @@ pub struct VmSnapshotConfig { pub destination_url: String, } +#[derive(Clone, Deserialize, Serialize, Default, Debug)] +pub struct VmCoredumpData { + /// The coredump destination file + pub destination_url: String, +} + #[derive(Clone, Deserialize, Serialize, Default, Debug)] pub struct VmReceiveMigrationData { /// URL for the reception of migration state @@ -310,6 +319,10 @@ pub enum ApiRequest { /// Restore from a VM snapshot VmRestore(Arc, Sender), + /// Take a VM coredump + #[cfg(feature = "guest_debug")] + VmCoredump(Arc, Sender), + /// Incoming migration VmReceiveMigration(Arc, Sender), @@ -402,6 +415,10 @@ pub enum VmAction { /// Snapshot VM Snapshot(Arc), + /// Coredump VM + #[cfg(feature = "guest_debug")] + Coredump(Arc), + /// Incoming migration ReceiveMigration(Arc), @@ -441,6 +458,8 @@ fn vm_action( ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender), Restore(v) => ApiRequest::VmRestore(v, response_sender), Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender), + #[cfg(feature = "guest_debug")] + Coredump(v) => ApiRequest::VmCoredump(v, response_sender), ReceiveMigration(v) => ApiRequest::VmReceiveMigration(v, response_sender), SendMigration(v) => ApiRequest::VmSendMigration(v, response_sender), PowerButton => ApiRequest::VmPowerButton(response_sender), @@ -526,6 +545,15 @@ pub fn vm_restore( vm_action(api_evt, api_sender, VmAction::Restore(data)) } +#[cfg(feature = "guest_debug")] +pub fn vm_coredump( + api_evt: EventFd, + api_sender: Sender, + data: Arc, +) -> ApiResult> { + vm_action(api_evt, api_sender, VmAction::Coredump(data)) +} + pub fn vm_info(api_evt: EventFd, api_sender: Sender) -> ApiResult { let (response_sender, response_receiver) = channel(); diff --git a/vmm/src/coredump.rs b/vmm/src/coredump.rs index 62080ed2f..d51fc4ade 100644 --- a/vmm/src/coredump.rs +++ b/vmm/src/coredump.rs @@ -79,7 +79,6 @@ pub struct X86_64UserRegs { unsafe impl ByteValued for X86_64UserRegs {} #[repr(C)] -#[allow(dead_code)] pub struct X86_64ElfPrStatus { pub pad1: [u8; 32], pub pid: u32, diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index a9830ac27..d61683bd3 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -18,6 +18,8 @@ use crate::config::{ add_to_config, DeviceConfig, DiskConfig, FsConfig, NetConfig, PmemConfig, RestoreConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, }; +#[cfg(feature = "guest_debug")] +use crate::coredump::GuestDebuggable; #[cfg(all(feature = "kvm", target_arch = "x86_64"))] use crate::migration::get_vm_snapshot; use crate::migration::{recv_vm_config, recv_vm_state}; @@ -562,6 +564,15 @@ impl Vmm { } } + #[cfg(feature = "guest_debug")] + fn vm_coredump(&mut self, destination_url: &str) -> result::Result<(), VmError> { + if let Some(ref mut vm) = self.vm { + vm.coredump(destination_url).map_err(VmError::Coredump) + } else { + Err(VmError::VmNotRunning) + } + } + fn vm_shutdown(&mut self) -> result::Result<(), VmError> { if let Some(ref mut vm) = self.vm.take() { vm.shutdown() @@ -1684,6 +1695,15 @@ impl Vmm { sender.send(response).map_err(Error::ApiResponseSend)?; } + #[cfg(feature = "guest_debug")] + ApiRequest::VmCoredump(coredump_data, sender) => { + let response = self + .vm_coredump(&coredump_data.destination_url) + .map_err(ApiError::VmCoredump) + .map(|_| ApiResponsePayload::Empty); + + sender.send(response).map_err(Error::ApiResponseSend)?; + } ApiRequest::VmmShutdown(sender) => { let response = self .vmm_shutdown()