mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-03 20:15:45 +00:00
devices: Lock the BtreeMap inside to avoid deadlocks
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
733e636f02
commit
1870eb4295
@ -10,7 +10,7 @@
|
|||||||
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||||
use std::collections::btree_map::BTreeMap;
|
use std::collections::btree_map::BTreeMap;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
/// Trait for devices that respond to reads or writes in an arbitrary address space.
|
/// Trait for devices that respond to reads or writes in an arbitrary address space.
|
||||||
///
|
///
|
||||||
@ -79,30 +79,30 @@ impl PartialOrd for BusRange {
|
|||||||
///
|
///
|
||||||
/// This doesn't have any restrictions on what kind of device or address space this applies to. The
|
/// This doesn't have any restrictions on what kind of device or address space this applies to. The
|
||||||
/// only restriction is that no two devices can overlap in this address space.
|
/// only restriction is that no two devices can overlap in this address space.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Default)]
|
||||||
pub struct Bus {
|
pub struct Bus {
|
||||||
devices: BTreeMap<BusRange, Arc<Mutex<dyn BusDevice>>>,
|
devices: RwLock<BTreeMap<BusRange, Arc<Mutex<dyn BusDevice>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
/// Constructs an a bus with an empty address space.
|
/// Constructs an a bus with an empty address space.
|
||||||
pub fn new() -> Bus {
|
pub fn new() -> Bus {
|
||||||
Bus {
|
Bus {
|
||||||
devices: BTreeMap::new(),
|
devices: RwLock::new(BTreeMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_before(&self, addr: u64) -> Option<(BusRange, &Arc<Mutex<dyn BusDevice>>)> {
|
fn first_before(&self, addr: u64) -> Option<(BusRange, Arc<Mutex<dyn BusDevice>>)> {
|
||||||
let (range, dev) = self
|
let devices = self.devices.read().unwrap();
|
||||||
.devices
|
let (range, dev) = devices
|
||||||
.range(..=BusRange { base: addr, len: 1 })
|
.range(..=BusRange { base: addr, len: 1 })
|
||||||
.rev()
|
.rev()
|
||||||
.next()?;
|
.next()?;
|
||||||
Some((*range, dev))
|
Some((*range, dev.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn resolve(&self, addr: u64) -> Option<(u64, u64, &Arc<Mutex<dyn BusDevice>>)> {
|
pub fn resolve(&self, addr: u64) -> Option<(u64, u64, Arc<Mutex<dyn BusDevice>>)> {
|
||||||
if let Some((range, dev)) = self.first_before(addr) {
|
if let Some((range, dev)) = self.first_before(addr) {
|
||||||
let offset = addr - range.base;
|
let offset = addr - range.base;
|
||||||
if offset < range.len {
|
if offset < range.len {
|
||||||
@ -113,7 +113,7 @@ impl Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Puts the given device at the given address space.
|
/// Puts the given device at the given address space.
|
||||||
pub fn insert(&mut self, device: Arc<Mutex<dyn BusDevice>>, base: u64, len: u64) -> Result<()> {
|
pub fn insert(&self, device: Arc<Mutex<dyn BusDevice>>, base: u64, len: u64) -> Result<()> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Err(Error::ZeroSizedRange);
|
return Err(Error::ZeroSizedRange);
|
||||||
}
|
}
|
||||||
@ -121,6 +121,8 @@ impl Bus {
|
|||||||
// Reject all cases where the new device's range overlaps with an existing device.
|
// Reject all cases where the new device's range overlaps with an existing device.
|
||||||
if self
|
if self
|
||||||
.devices
|
.devices
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(range, _dev)| range.overlaps(base, len))
|
.any(|(range, _dev)| range.overlaps(base, len))
|
||||||
{
|
{
|
||||||
@ -129,6 +131,8 @@ impl Bus {
|
|||||||
|
|
||||||
if self
|
if self
|
||||||
.devices
|
.devices
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
.insert(BusRange { base, len }, device)
|
.insert(BusRange { base, len }, device)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
@ -139,14 +143,14 @@ impl Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the device at the given address space range.
|
/// Removes the device at the given address space range.
|
||||||
pub fn remove(&mut self, base: u64, len: u64) -> Result<()> {
|
pub fn remove(&self, base: u64, len: u64) -> Result<()> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Err(Error::ZeroSizedRange);
|
return Err(Error::ZeroSizedRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bus_range = BusRange { base, len };
|
let bus_range = BusRange { base, len };
|
||||||
|
|
||||||
if self.devices.remove(&bus_range).is_none() {
|
if self.devices.write().unwrap().remove(&bus_range).is_none() {
|
||||||
return Err(Error::MissingAddressRange);
|
return Err(Error::MissingAddressRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +159,7 @@ impl Bus {
|
|||||||
|
|
||||||
/// Updates the address range for an existing device.
|
/// Updates the address range for an existing device.
|
||||||
pub fn update_range(
|
pub fn update_range(
|
||||||
&mut self,
|
&self,
|
||||||
old_base: u64,
|
old_base: u64,
|
||||||
old_len: u64,
|
old_len: u64,
|
||||||
new_base: u64,
|
new_base: u64,
|
||||||
@ -230,7 +234,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bus_insert() {
|
fn bus_insert() {
|
||||||
let mut bus = Bus::new();
|
let bus = Bus::new();
|
||||||
let dummy = Arc::new(Mutex::new(DummyDevice));
|
let dummy = Arc::new(Mutex::new(DummyDevice));
|
||||||
assert!(bus.insert(dummy.clone(), 0x10, 0).is_err());
|
assert!(bus.insert(dummy.clone(), 0x10, 0).is_err());
|
||||||
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
|
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
|
||||||
@ -251,7 +255,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bus_read_write() {
|
fn bus_read_write() {
|
||||||
let mut bus = Bus::new();
|
let bus = Bus::new();
|
||||||
let dummy = Arc::new(Mutex::new(DummyDevice));
|
let dummy = Arc::new(Mutex::new(DummyDevice));
|
||||||
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
|
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
|
||||||
assert!(bus.read(0x10, &mut [0, 0, 0, 0]));
|
assert!(bus.read(0x10, &mut [0, 0, 0, 0]));
|
||||||
@ -268,7 +272,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bus_read_write_values() {
|
fn bus_read_write_values() {
|
||||||
let mut bus = Bus::new();
|
let bus = Bus::new();
|
||||||
let dummy = Arc::new(Mutex::new(ConstantDevice));
|
let dummy = Arc::new(Mutex::new(ConstantDevice));
|
||||||
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
|
assert!(bus.insert(dummy.clone(), 0x10, 0x10).is_ok());
|
||||||
|
|
||||||
@ -282,7 +286,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn busrange_cmp_and_clone() {
|
fn busrange_cmp() {
|
||||||
let range = BusRange { base: 0x10, len: 2 };
|
let range = BusRange { base: 0x10, len: 2 };
|
||||||
assert_eq!(range, BusRange { base: 0x10, len: 3 });
|
assert_eq!(range, BusRange { base: 0x10, len: 3 });
|
||||||
assert_eq!(range, BusRange { base: 0x10, len: 2 });
|
assert_eq!(range, BusRange { base: 0x10, len: 2 });
|
||||||
@ -292,17 +296,14 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(range, range.clone());
|
assert_eq!(range, range.clone());
|
||||||
|
|
||||||
let mut bus = Bus::new();
|
let bus = Bus::new();
|
||||||
let mut data = [1, 2, 3, 4];
|
let mut data = [1, 2, 3, 4];
|
||||||
assert!(bus
|
assert!(bus
|
||||||
.insert(Arc::new(Mutex::new(DummyDevice)), 0x10, 0x10)
|
.insert(Arc::new(Mutex::new(DummyDevice)), 0x10, 0x10)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert!(bus.write(0x10, &mut data));
|
assert!(bus.write(0x10, &mut data));
|
||||||
let bus_clone = bus.clone();
|
|
||||||
assert!(bus.read(0x10, &mut data));
|
assert!(bus.read(0x10, &mut data));
|
||||||
assert_eq!(data, [1, 2, 3, 4]);
|
assert_eq!(data, [1, 2, 3, 4]);
|
||||||
assert!(bus_clone.read(0x10, &mut data));
|
|
||||||
assert_eq!(data, [1, 2, 3, 4]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -89,8 +89,8 @@ impl PciBus {
|
|||||||
pub fn register_mapping(
|
pub fn register_mapping(
|
||||||
&self,
|
&self,
|
||||||
dev: Arc<Mutex<dyn BusDevice>>,
|
dev: Arc<Mutex<dyn BusDevice>>,
|
||||||
io_bus: &mut devices::Bus,
|
io_bus: &devices::Bus,
|
||||||
mmio_bus: &mut devices::Bus,
|
mmio_bus: &devices::Bus,
|
||||||
bars: Vec<(GuestAddress, GuestUsize, PciBarRegionType)>,
|
bars: Vec<(GuestAddress, GuestUsize, PciBarRegionType)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for (address, size, type_) in bars {
|
for (address, size, type_) in bars {
|
||||||
|
@ -168,8 +168,8 @@ pub enum DeviceManagerError {
|
|||||||
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
|
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
|
||||||
|
|
||||||
struct BusInfo<'a> {
|
struct BusInfo<'a> {
|
||||||
io: &'a mut devices::Bus,
|
io: &'a Arc<devices::Bus>,
|
||||||
mmio: &'a mut devices::Bus,
|
mmio: &'a Arc<devices::Bus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InterruptInfo<'a> {
|
struct InterruptInfo<'a> {
|
||||||
@ -276,8 +276,8 @@ impl Console {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct DeviceManager {
|
pub struct DeviceManager {
|
||||||
io_bus: devices::Bus,
|
io_bus: Arc<devices::Bus>,
|
||||||
mmio_bus: devices::Bus,
|
mmio_bus: Arc<devices::Bus>,
|
||||||
|
|
||||||
// Console abstraction
|
// Console abstraction
|
||||||
console: Arc<Console>,
|
console: Arc<Console>,
|
||||||
@ -306,8 +306,8 @@ impl DeviceManager {
|
|||||||
_exit_evt: &EventFd,
|
_exit_evt: &EventFd,
|
||||||
reset_evt: &EventFd,
|
reset_evt: &EventFd,
|
||||||
) -> DeviceManagerResult<Self> {
|
) -> DeviceManagerResult<Self> {
|
||||||
let mut io_bus = devices::Bus::new();
|
let mut io_bus = Arc::new(devices::Bus::new());
|
||||||
let mut mmio_bus = devices::Bus::new();
|
let mut mmio_bus = Arc::new(devices::Bus::new());
|
||||||
|
|
||||||
let mut buses = BusInfo {
|
let mut buses = BusInfo {
|
||||||
io: &mut io_bus,
|
io: &mut io_bus,
|
||||||
@ -1035,8 +1035,13 @@ impl DeviceManager {
|
|||||||
pci.add_device(vfio_pci_device.clone())
|
pci.add_device(vfio_pci_device.clone())
|
||||||
.map_err(DeviceManagerError::AddPciDevice)?;
|
.map_err(DeviceManagerError::AddPciDevice)?;
|
||||||
|
|
||||||
pci.register_mapping(vfio_pci_device.clone(), buses.io, buses.mmio, bars)
|
pci.register_mapping(
|
||||||
.map_err(DeviceManagerError::AddPciDevice)?;
|
vfio_pci_device.clone(),
|
||||||
|
buses.io.as_ref(),
|
||||||
|
buses.mmio.as_ref(),
|
||||||
|
bars,
|
||||||
|
)
|
||||||
|
.map_err(DeviceManagerError::AddPciDevice)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(iommu_attached_device_ids)
|
Ok(iommu_attached_device_ids)
|
||||||
@ -1178,8 +1183,8 @@ impl DeviceManager {
|
|||||||
|
|
||||||
pci.register_mapping(
|
pci.register_mapping(
|
||||||
virtio_pci_device.clone(),
|
virtio_pci_device.clone(),
|
||||||
&mut buses.io,
|
buses.io.as_ref(),
|
||||||
&mut buses.mmio,
|
buses.mmio.as_ref(),
|
||||||
bars,
|
bars,
|
||||||
)
|
)
|
||||||
.map_err(DeviceManagerError::AddPciDevice)?;
|
.map_err(DeviceManagerError::AddPciDevice)?;
|
||||||
@ -1250,11 +1255,11 @@ impl DeviceManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn io_bus(&self) -> &devices::Bus {
|
pub fn io_bus(&self) -> &Arc<devices::Bus> {
|
||||||
&self.io_bus
|
&self.io_bus
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mmio_bus(&self) -> &devices::Bus {
|
pub fn mmio_bus(&self) -> &Arc<devices::Bus> {
|
||||||
&self.mmio_bus
|
&self.mmio_bus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,8 +304,8 @@ impl CpuidPatch {
|
|||||||
pub struct Vcpu {
|
pub struct Vcpu {
|
||||||
fd: VcpuFd,
|
fd: VcpuFd,
|
||||||
id: u8,
|
id: u8,
|
||||||
io_bus: devices::Bus,
|
io_bus: Arc<devices::Bus>,
|
||||||
mmio_bus: devices::Bus,
|
mmio_bus: Arc<devices::Bus>,
|
||||||
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
||||||
vm_ts: std::time::Instant,
|
vm_ts: std::time::Instant,
|
||||||
}
|
}
|
||||||
@ -320,8 +320,8 @@ impl Vcpu {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
id: u8,
|
id: u8,
|
||||||
vm: &Vm,
|
vm: &Vm,
|
||||||
io_bus: devices::Bus,
|
io_bus: Arc<devices::Bus>,
|
||||||
mmio_bus: devices::Bus,
|
mmio_bus: Arc<devices::Bus>,
|
||||||
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
ioapic: Option<Arc<Mutex<ioapic::Ioapic>>>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let kvm_vcpu = vm.fd.create_vcpu(id).map_err(Error::VcpuFd)?;
|
let kvm_vcpu = vm.fd.create_vcpu(id).map_err(Error::VcpuFd)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user