mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: introduce ACPI CPU hotplug controller (fix deadlock)
Extract AcpiCpuHotplugController from CpuManager and move the BusDevice implementation to the new type. This separates VMM-internal vCPU management from the guest-visible ACPI CPU hotplug MMIO interface. Besides clarifying responsibilities and reducing technical debt, this fixes a rare deadlock involving pause handling and MMIO access. New responsibilities: - CpuManager manages VMM-internal vCPU lifecycle and coordination - AcpiCpuHotplugController implements the guest-visible ACPI CPU hotplug MMIO interface A vCPU thread may exit KVM_RUN to perform an MMIO access previously handled by CpuManager. If the VMM thread begins processing a `pause` event before that MMIO operation acquires access to CpuManager, CpuManager::pause() will block waiting for the vCPU thread to ACK the pause, while the vCPU thread is blocked waiting to complete the MMIO operation through the same CpuManager - which it can never lock - the VMM is deadlocked. This can occur during early boot or CPU hotplug when pause events race with MMIO accesses. The issue is rare and timing-dependent, but real. For reproducing: run `ch-remote pause|resume` in a loop while booting a Linux VM (via direct kernel boot). With the new design, these MMIO operations no longer depend on CpuManager, which removes the deadlock path entirely. On-behalf-of: SAP philipp.schuster@sap.com Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
This commit is contained in:
committed by
Rob Bradford
parent
6d0d4bc5e2
commit
5ff4696cea
@@ -124,7 +124,7 @@ use vm_virtio::{AccessPlatform, VirtioDeviceType};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::console_devices::{ConsoleDeviceError, ConsoleInfo, ConsoleTransport};
|
||||
use crate::cpu::{CPU_MANAGER_ACPI_SIZE, CpuManager};
|
||||
use crate::cpu::{AcpiCpuHotplugController, CPU_MANAGER_ACPI_SIZE, CpuManager};
|
||||
use crate::device_tree::{DeviceNode, DeviceTree};
|
||||
use crate::interrupt::{LegacyUserspaceInterruptManager, MsiInterruptManager};
|
||||
use crate::memory_manager::{Error as MemoryManagerError, MEMORY_MANAGER_ACPI_SIZE, MemoryManager};
|
||||
@@ -1026,6 +1026,10 @@ pub struct DeviceManager {
|
||||
// CPU Manager
|
||||
cpu_manager: Arc<Mutex<CpuManager>>,
|
||||
|
||||
/// Owned version needed to keep the bus device alive (the bus only holds
|
||||
/// a weak reference).
|
||||
_acpi_cpu_hotplug_controller: Arc<Mutex<AcpiCpuHotplugController>>,
|
||||
|
||||
// The virtio devices on the system
|
||||
virtio_devices: Vec<MetaVirtioDevice>,
|
||||
|
||||
@@ -1324,6 +1328,10 @@ impl DeviceManager {
|
||||
)?);
|
||||
}
|
||||
|
||||
let acpi_cpu_hotplug_controller =
|
||||
AcpiCpuHotplugController::new(&cpu_manager.lock().unwrap());
|
||||
let acpi_cpu_hotplug_controller = Arc::new(Mutex::new(acpi_cpu_hotplug_controller));
|
||||
|
||||
if dynamic {
|
||||
let acpi_address = address_manager
|
||||
.allocator
|
||||
@@ -1335,7 +1343,7 @@ impl DeviceManager {
|
||||
address_manager
|
||||
.mmio_bus
|
||||
.insert(
|
||||
cpu_manager.clone(),
|
||||
acpi_cpu_hotplug_controller.clone(),
|
||||
acpi_address.0,
|
||||
CPU_MANAGER_ACPI_SIZE as u64,
|
||||
)
|
||||
@@ -1429,6 +1437,7 @@ impl DeviceManager {
|
||||
fw_cfg: None,
|
||||
#[cfg(feature = "ivshmem")]
|
||||
ivshmem_device: None,
|
||||
_acpi_cpu_hotplug_controller: acpi_cpu_hotplug_controller,
|
||||
};
|
||||
|
||||
let device_manager = Arc::new(Mutex::new(device_manager));
|
||||
|
||||
Reference in New Issue
Block a user