vmm: drop device_tree mutex before acquiring pci_bus mutex

AddressManager::move_bar() acquires the device_tree mutex.
The function is called from PciConfigIo::config_space_write()/
PciConfigMmio::config_space_write() while the pci_bus mutex
is acquired.
The functions DeviceManager::pci_resources()/eject_device()
acquire these mutexes in reverse order, which leads to a deadlock.

Fixes: #6775

Signed-off-by: Alexandru Matei <alexandru.matei@uipath.com>
This commit is contained in:
Alexandru Matei 2024-10-02 12:30:50 +03:00 committed by Rob Bradford
parent 0dc3634b7b
commit c891dcb947

View File

@ -3857,29 +3857,33 @@ impl DeviceManager {
) -> DeviceManagerResult<(u16, PciBdf, Option<Vec<Resource>>)> { ) -> DeviceManagerResult<(u16, PciBdf, Option<Vec<Resource>>)> {
// Look for the id in the device tree. If it can be found, that means // Look for the id in the device tree. If it can be found, that means
// the device is being restored, otherwise it's created from scratch. // the device is being restored, otherwise it's created from scratch.
Ok( let (pci_device_bdf, resources) =
if let Some(node) = self.device_tree.lock().unwrap().get(id) { if let Some(node) = self.device_tree.lock().unwrap().get(id) {
info!("Restoring virtio-pci {} resources", id); info!("Restoring virtio-pci {} resources", id);
let pci_device_bdf: PciBdf = node let pci_device_bdf: PciBdf = node
.pci_bdf .pci_bdf
.ok_or(DeviceManagerError::MissingDeviceNodePciBdf)?; .ok_or(DeviceManagerError::MissingDeviceNodePciBdf)?;
let pci_segment_id = pci_device_bdf.segment(); (Some(pci_device_bdf), Some(node.resources.clone()))
self.pci_segments[pci_segment_id as usize]
.pci_bus
.lock()
.unwrap()
.get_device_id(pci_device_bdf.device() as usize)
.map_err(DeviceManagerError::GetPciDeviceId)?;
(pci_segment_id, pci_device_bdf, Some(node.resources.clone()))
} else { } else {
let pci_device_bdf = (None, None)
self.pci_segments[pci_segment_id as usize].next_device_bdf()?; };
(pci_segment_id, pci_device_bdf, None) Ok(if let Some(pci_device_bdf) = pci_device_bdf {
}, let pci_segment_id = pci_device_bdf.segment();
)
self.pci_segments[pci_segment_id as usize]
.pci_bus
.lock()
.unwrap()
.get_device_id(pci_device_bdf.device() as usize)
.map_err(DeviceManagerError::GetPciDeviceId)?;
(pci_segment_id, pci_device_bdf, resources)
} else {
let pci_device_bdf = self.pci_segments[pci_segment_id as usize].next_device_bdf()?;
(pci_segment_id, pci_device_bdf, None)
})
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -4098,30 +4102,34 @@ impl DeviceManager {
.put_device_id(device_id as usize) .put_device_id(device_id as usize)
.map_err(DeviceManagerError::PutPciDeviceId)?; .map_err(DeviceManagerError::PutPciDeviceId)?;
// Remove the device from the device tree along with its children. let (pci_device_handle, id) = {
let mut device_tree = self.device_tree.lock().unwrap(); // Remove the device from the device tree along with its children.
let pci_device_node = device_tree let mut device_tree = self.device_tree.lock().unwrap();
.remove_node_by_pci_bdf(pci_device_bdf) let pci_device_node = device_tree
.ok_or(DeviceManagerError::MissingPciDevice)?; .remove_node_by_pci_bdf(pci_device_bdf)
.ok_or(DeviceManagerError::MissingPciDevice)?;
// For VFIO and vfio-user the PCI device id is the id. // For VFIO and vfio-user the PCI device id is the id.
// For virtio we overwrite it later as we want the id of the // For virtio we overwrite it later as we want the id of the
// underlying device. // underlying device.
let mut id = pci_device_node.id; let mut id = pci_device_node.id;
let pci_device_handle = pci_device_node let pci_device_handle = pci_device_node
.pci_device_handle .pci_device_handle
.ok_or(DeviceManagerError::MissingPciDevice)?; .ok_or(DeviceManagerError::MissingPciDevice)?;
if matches!(pci_device_handle, PciDeviceHandle::Virtio(_)) { if matches!(pci_device_handle, PciDeviceHandle::Virtio(_)) {
// The virtio-pci device has a single child // The virtio-pci device has a single child
if !pci_device_node.children.is_empty() { if !pci_device_node.children.is_empty() {
assert_eq!(pci_device_node.children.len(), 1); assert_eq!(pci_device_node.children.len(), 1);
let child_id = &pci_device_node.children[0]; let child_id = &pci_device_node.children[0];
id.clone_from(child_id); id.clone_from(child_id);
}
} }
} for child in pci_device_node.children.iter() {
for child in pci_device_node.children.iter() { device_tree.remove(child);
device_tree.remove(child); }
}
(pci_device_handle, id)
};
let mut iommu_attached = false; let mut iommu_attached = false;
if let Some((_, iommu_attached_devices)) = &self.iommu_attached_devices { if let Some((_, iommu_attached_devices)) = &self.iommu_attached_devices {