mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: device_manager: reject duplicate socket in add_user_device
Calling vm.add-user-device a second time with a socket path already in use makes the VMM thread block indefinitely inside vfio_user::Client::new(). libvfio-user servers (SPDK, the reference libvfio-user daemon) accept a single active client per socket, so the second connect(2) succeeds at the OS level but the handshake recvmsg(2) waits for a response that never arrives. All subsequent API requests queue behind the stuck VMM event loop and also hang (vm.info, vmm.ping, vm.remove-device). The VM itself keeps running on vcpu threads, making the symptom confusing: the guest looks healthy, only the API is unreachable. This is easy to hit from management software that uses an idempotent reconcile / ensure pattern for user devices. Reject the call up-front when another user_device already has the same socket path, returning an HTTP 500 with a descriptive UserDeviceSocketInUse error in milliseconds instead of hanging. Signed-off-by: Max Makarov <maxpain@linux.com>
This commit is contained in:
committed by
Rob Bradford
parent
e2c51042d3
commit
cdfedfaab2
@@ -657,6 +657,10 @@ pub enum DeviceManagerError {
|
|||||||
#[error("Invalid identifier: {0}")]
|
#[error("Invalid identifier: {0}")]
|
||||||
InvalidIdentifier(String),
|
InvalidIdentifier(String),
|
||||||
|
|
||||||
|
/// vfio-user socket path already in use by another user device.
|
||||||
|
#[error("vfio-user socket path already in use: {0:?}")]
|
||||||
|
UserDeviceSocketInUse(std::path::PathBuf),
|
||||||
|
|
||||||
/// Error activating virtio device
|
/// Error activating virtio device
|
||||||
#[error("Error activating virtio device")]
|
#[error("Error activating virtio device")]
|
||||||
VirtioActivate(#[source] ActivateError),
|
VirtioActivate(#[source] ActivateError),
|
||||||
@@ -4707,6 +4711,17 @@ impl DeviceManager {
|
|||||||
) -> DeviceManagerResult<PciDeviceInfo> {
|
) -> DeviceManagerResult<PciDeviceInfo> {
|
||||||
self.validate_identifier(&device_cfg.pci_common.id)?;
|
self.validate_identifier(&device_cfg.pci_common.id)?;
|
||||||
|
|
||||||
|
// Reject duplicate socket up-front: libvfio-user servers accept a
|
||||||
|
// single client, so a second Client::new() on the same socket blocks
|
||||||
|
// indefinitely in the handshake recvmsg() and hangs the VMM thread.
|
||||||
|
if let Some(existing) = &self.config.lock().unwrap().user_devices
|
||||||
|
&& existing.iter().any(|d| d.socket == device_cfg.socket)
|
||||||
|
{
|
||||||
|
return Err(DeviceManagerError::UserDeviceSocketInUse(
|
||||||
|
device_cfg.socket.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let (bdf, device_name) = self.add_vfio_user_device(device_cfg)?;
|
let (bdf, device_name) = self.add_vfio_user_device(device_cfg)?;
|
||||||
|
|
||||||
// Update the PCIU bitmap
|
// Update the PCIU bitmap
|
||||||
|
|||||||
Reference in New Issue
Block a user