mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Convert virtio devices to Arc<Mutex<T>>
Migratable devices can be virtio or legacy devices. In any case, they can potentially be tracked through one of the IO bus as an Arc<Mutex<dyn BusDevice>>. In order for the DeviceManager to also keep track of such devices as Migratable trait objects, they must be shared as mutable atomic references, i.e. Arc<Mutex<T>>. That forces all Migratable objects to be tracked as Arc<Mutex<dyn Migratable>>. Virtio devices are typically migratable, and thus for them to be referenced by the DeviceManager, they now should be built as Arc<Mutex<VirtioDevice>>. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use libc::EFD_NONBLOCK;
|
||||
@@ -38,7 +38,7 @@ const MMIO_VERSION: u32 = 2;
|
||||
/// Typically one page (4096 bytes) of MMIO address space is sufficient to handle this transport
|
||||
/// and inner virtio device.
|
||||
pub struct MmioDevice {
|
||||
device: Box<dyn VirtioDevice>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
device_activated: bool,
|
||||
|
||||
features_select: u32,
|
||||
@@ -57,13 +57,15 @@ impl MmioDevice {
|
||||
/// Constructs a new MMIO transport for the given virtio device.
|
||||
pub fn new(
|
||||
mem: Arc<RwLock<GuestMemoryMmap>>,
|
||||
device: Box<dyn VirtioDevice>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) -> Result<MmioDevice> {
|
||||
let device_clone = device.clone();
|
||||
let locked_device = device_clone.lock().unwrap();
|
||||
let mut queue_evts = Vec::new();
|
||||
for _ in device.queue_max_sizes().iter() {
|
||||
for _ in locked_device.queue_max_sizes().iter() {
|
||||
queue_evts.push(EventFd::new(EFD_NONBLOCK)?)
|
||||
}
|
||||
let queues = device
|
||||
let queues = locked_device
|
||||
.queue_max_sizes()
|
||||
.iter()
|
||||
.map(|&s| Queue::new(s))
|
||||
@@ -158,10 +160,10 @@ impl BusDevice for MmioDevice {
|
||||
let v = match offset {
|
||||
0x0 => MMIO_MAGIC_VALUE,
|
||||
0x04 => MMIO_VERSION,
|
||||
0x08 => self.device.device_type(),
|
||||
0x08 => self.device.lock().unwrap().device_type(),
|
||||
0x0c => VENDOR_ID, // vendor id
|
||||
0x10 => {
|
||||
self.device.features(self.features_select)
|
||||
self.device.lock().unwrap().features(self.features_select)
|
||||
| if self.features_select == 1 { 0x1 } else { 0x0 }
|
||||
}
|
||||
0x34 => self.with_queue(0, |q| u32::from(q.get_max_size())),
|
||||
@@ -176,7 +178,11 @@ impl BusDevice for MmioDevice {
|
||||
};
|
||||
LittleEndian::write_u32(data, v);
|
||||
}
|
||||
0x100..=0xfff => self.device.read_config(offset - 0x100, data),
|
||||
0x100..=0xfff => self
|
||||
.device
|
||||
.lock()
|
||||
.unwrap()
|
||||
.read_config(offset - 0x100, data),
|
||||
_ => {
|
||||
warn!(
|
||||
"invalid virtio mmio read: 0x{:x}:0x{:x}",
|
||||
@@ -202,7 +208,11 @@ impl BusDevice for MmioDevice {
|
||||
let v = LittleEndian::read_u32(data);
|
||||
match offset {
|
||||
0x14 => self.features_select = v,
|
||||
0x20 => self.device.ack_features(self.acked_features_select, v),
|
||||
0x20 => self
|
||||
.device
|
||||
.lock()
|
||||
.unwrap()
|
||||
.ack_features(self.acked_features_select, v),
|
||||
0x24 => self.acked_features_select = v,
|
||||
0x30 => self.queue_select = v,
|
||||
0x38 => mut_q = self.with_queue_mut(|q| q.size = v as u16),
|
||||
@@ -224,7 +234,13 @@ impl BusDevice for MmioDevice {
|
||||
}
|
||||
}
|
||||
}
|
||||
0x100..=0xfff => return self.device.write_config(offset - 0x100, data),
|
||||
0x100..=0xfff => {
|
||||
return self
|
||||
.device
|
||||
.lock()
|
||||
.unwrap()
|
||||
.write_config(offset - 0x100, data)
|
||||
}
|
||||
_ => {
|
||||
warn!(
|
||||
"invalid virtio mmio write: 0x{:x}:0x{:x}",
|
||||
@@ -244,6 +260,8 @@ impl BusDevice for MmioDevice {
|
||||
if self.mem.is_some() {
|
||||
let mem = self.mem.as_ref().unwrap().clone();
|
||||
self.device
|
||||
.lock()
|
||||
.unwrap()
|
||||
.activate(
|
||||
mem,
|
||||
interrupt_cb,
|
||||
|
||||
@@ -9,7 +9,7 @@ extern crate byteorder;
|
||||
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use std::sync::atomic::{AtomicU16, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
use crate::{Queue, VirtioDevice};
|
||||
@@ -51,7 +51,7 @@ impl VirtioPciCommonConfig {
|
||||
offset: u64,
|
||||
data: &mut [u8],
|
||||
queues: &mut Vec<Queue>,
|
||||
device: &mut dyn VirtioDevice,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
assert!(data.len() <= 8);
|
||||
|
||||
@@ -81,7 +81,7 @@ impl VirtioPciCommonConfig {
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
queues: &mut Vec<Queue>,
|
||||
device: &mut dyn VirtioDevice,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
assert!(data.len() <= 8);
|
||||
|
||||
@@ -156,15 +156,16 @@ impl VirtioPciCommonConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_common_config_dword(&self, offset: u64, device: &dyn VirtioDevice) -> u32 {
|
||||
fn read_common_config_dword(&self, offset: u64, device: Arc<Mutex<dyn VirtioDevice>>) -> u32 {
|
||||
debug!("read_common_config_dword: offset 0x{:x}", offset);
|
||||
match offset {
|
||||
0x00 => self.device_feature_select,
|
||||
0x04 => {
|
||||
let locked_device = device.lock().unwrap();
|
||||
// Only 64 bits of features (2 pages) are defined for now, so limit
|
||||
// device_feature_select to avoid shifting by 64 or more bits.
|
||||
if self.device_feature_select < 2 {
|
||||
device.features(self.device_feature_select)
|
||||
locked_device.features(self.device_feature_select)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@@ -182,7 +183,7 @@ impl VirtioPciCommonConfig {
|
||||
offset: u64,
|
||||
value: u32,
|
||||
queues: &mut Vec<Queue>,
|
||||
device: &mut dyn VirtioDevice,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
) {
|
||||
debug!("write_common_config_dword: offset 0x{:x}", offset);
|
||||
fn hi(v: &mut GuestAddress, x: u32) {
|
||||
@@ -198,7 +199,8 @@ impl VirtioPciCommonConfig {
|
||||
0x08 => self.driver_feature_select = value,
|
||||
0x0c => {
|
||||
if self.driver_feature_select < 2 {
|
||||
device.ack_features(self.driver_feature_select, value);
|
||||
let mut locked_device = device.lock().unwrap();
|
||||
locked_device.ack_features(self.driver_feature_select, value);
|
||||
} else {
|
||||
warn!(
|
||||
"invalid ack_features (page {}, value 0x{:x})",
|
||||
|
||||
@@ -225,7 +225,7 @@ pub struct VirtioPciDevice {
|
||||
msix_num: u16,
|
||||
|
||||
// Virtio device reference and status
|
||||
device: Box<dyn VirtioDevice>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
device_activated: bool,
|
||||
|
||||
// PCI interrupts.
|
||||
@@ -250,15 +250,17 @@ impl VirtioPciDevice {
|
||||
/// Constructs a new PCI transport for the given virtio device.
|
||||
pub fn new(
|
||||
memory: Arc<RwLock<GuestMemoryMmap>>,
|
||||
device: Box<dyn VirtioDevice>,
|
||||
device: Arc<Mutex<dyn VirtioDevice>>,
|
||||
msix_num: u16,
|
||||
iommu_mapping_cb: Option<Arc<VirtioIommuRemapping>>,
|
||||
) -> Result<Self> {
|
||||
let device_clone = device.clone();
|
||||
let locked_device = device_clone.lock().unwrap();
|
||||
let mut queue_evts = Vec::new();
|
||||
for _ in device.queue_max_sizes().iter() {
|
||||
for _ in locked_device.queue_max_sizes().iter() {
|
||||
queue_evts.push(EventFd::new(EFD_NONBLOCK)?)
|
||||
}
|
||||
let queues = device
|
||||
let queues = locked_device
|
||||
.queue_max_sizes()
|
||||
.iter()
|
||||
.map(|&s| {
|
||||
@@ -268,7 +270,7 @@ impl VirtioPciDevice {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + device.device_type() as u16;
|
||||
let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + locked_device.device_type() as u16;
|
||||
|
||||
let (msix_config, msix_config_clone) = if msix_num > 0 {
|
||||
let msix_config = Arc::new(Mutex::new(MsixConfig::new(msix_num)));
|
||||
@@ -282,7 +284,7 @@ impl VirtioPciDevice {
|
||||
// The block devices should be given a 32-bit BAR so that they are easily accessible
|
||||
// to firmware without requiring excessive identity mapping.
|
||||
let mut use_64bit_bar = true;
|
||||
let (class, subclass) = match VirtioDeviceType::from(device.device_type()) {
|
||||
let (class, subclass) = match VirtioDeviceType::from(locked_device.device_type()) {
|
||||
VirtioDeviceType::TYPE_NET => (
|
||||
PciClassCode::NetworkController,
|
||||
&PciNetworkControllerSubclass::EthernetController as &dyn PciSubclass,
|
||||
@@ -556,6 +558,8 @@ impl PciDevice for VirtioPciDevice {
|
||||
) -> std::result::Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError>
|
||||
{
|
||||
let mut ranges = Vec::new();
|
||||
let device_clone = self.device.clone();
|
||||
let device = device_clone.lock().unwrap();
|
||||
|
||||
// Allocate the virtio-pci capability BAR.
|
||||
// See http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-740004
|
||||
@@ -589,7 +593,7 @@ impl PciDevice for VirtioPciDevice {
|
||||
self.add_pci_capabilities(virtio_pci_bar)?;
|
||||
|
||||
// Allocate a dedicated BAR if there are some shared memory regions.
|
||||
if let Some(shm_list) = self.device.get_shm_regions() {
|
||||
if let Some(shm_list) = device.get_shm_regions() {
|
||||
let config = PciBarConfiguration::default()
|
||||
.set_register_index(2)
|
||||
.set_address(shm_list.addr.raw_value())
|
||||
@@ -622,7 +626,7 @@ impl PciDevice for VirtioPciDevice {
|
||||
o - COMMON_CONFIG_BAR_OFFSET,
|
||||
data,
|
||||
&mut self.queues,
|
||||
self.device.as_mut(),
|
||||
self.device.clone(),
|
||||
),
|
||||
o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
|
||||
if let Some(v) = data.get_mut(0) {
|
||||
@@ -633,7 +637,8 @@ impl PciDevice for VirtioPciDevice {
|
||||
o if DEVICE_CONFIG_BAR_OFFSET <= o
|
||||
&& o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
|
||||
{
|
||||
self.device.read_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
|
||||
let device = self.device.lock().unwrap();
|
||||
device.read_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
|
||||
}
|
||||
o if NOTIFICATION_BAR_OFFSET <= o
|
||||
&& o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
|
||||
@@ -666,7 +671,7 @@ impl PciDevice for VirtioPciDevice {
|
||||
o - COMMON_CONFIG_BAR_OFFSET,
|
||||
data,
|
||||
&mut self.queues,
|
||||
self.device.as_mut(),
|
||||
self.device.clone(),
|
||||
),
|
||||
o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
|
||||
if let Some(v) = data.get(0) {
|
||||
@@ -677,7 +682,8 @@ impl PciDevice for VirtioPciDevice {
|
||||
o if DEVICE_CONFIG_BAR_OFFSET <= o
|
||||
&& o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
|
||||
{
|
||||
self.device.write_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
|
||||
let mut device = self.device.lock().unwrap();
|
||||
device.write_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
|
||||
}
|
||||
o if NOTIFICATION_BAR_OFFSET <= o
|
||||
&& o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
|
||||
@@ -707,7 +713,8 @@ impl PciDevice for VirtioPciDevice {
|
||||
if let Some(interrupt_cb) = self.interrupt_cb.take() {
|
||||
if self.memory.is_some() {
|
||||
let mem = self.memory.as_ref().unwrap().clone();
|
||||
self.device
|
||||
let mut device = self.device.lock().unwrap();
|
||||
device
|
||||
.activate(
|
||||
mem,
|
||||
interrupt_cb,
|
||||
@@ -722,7 +729,8 @@ impl PciDevice for VirtioPciDevice {
|
||||
|
||||
// Device has been reset by the driver
|
||||
if self.device_activated && self.is_driver_init() {
|
||||
if let Some((interrupt_cb, mut queue_evts)) = self.device.reset() {
|
||||
let mut device = self.device.lock().unwrap();
|
||||
if let Some((interrupt_cb, mut queue_evts)) = device.reset() {
|
||||
// Upon reset the device returns its interrupt EventFD and it's queue EventFDs
|
||||
self.interrupt_cb = Some(interrupt_cb);
|
||||
self.queue_evts.append(&mut queue_evts);
|
||||
|
||||
Reference in New Issue
Block a user