devices: Lock the BtreeMap inside to avoid deadlocks

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-10-23 14:06:13 -07:00 committed by Samuel Ortiz
parent 733e636f02
commit 1870eb4295
4 changed files with 45 additions and 39 deletions

View File

@ -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]

View File

@ -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 {

View File

@ -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
} }

View File

@ -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)?;