vmm, pci: Implement virtio-mem support for vfio-user

Implement the infrastructure that lets a virtio-mem device map the guest
memory into the device. This is necessary since with virtio-mem zones
memory can be added or removed and the vfio-user device must be
informed.

Fixes: #3025

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-08-11 10:53:21 +00:00
parent e9d67dc405
commit 43365ade2e
4 changed files with 86 additions and 4 deletions

View File

@ -26,7 +26,7 @@ pub use self::device::{
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
pub use self::vfio::{VfioPciDevice, VfioPciError};
pub use self::vfio_user::{VfioUserPciDevice, VfioUserPciDeviceError};
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
/// PCI has four interrupt pins A->D.
#[derive(Copy, Clone)]

View File

@ -19,10 +19,14 @@ use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::VfioIrq;
use vfio_user::{Client, Error as VfioUserError};
use vm_allocator::SystemAllocator;
use vm_device::dma_mapping::ExternalDmaMapping;
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
use vm_device::BusDevice;
use vm_memory::bitmap::AtomicBitmap;
use vm_memory::{Address, GuestAddress, GuestMemoryRegion, GuestRegionMmap, GuestUsize};
use vm_memory::{
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
GuestUsize,
};
use vmm_sys_util::eventfd::EventFd;
pub struct VfioUserPciDevice {
@ -483,3 +487,57 @@ impl Drop for VfioUserPciDevice {
}
}
}
pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
client: Arc<Mutex<Client>>,
memory: Arc<M>,
}
impl<M: GuestAddressSpace> VfioUserDmaMapping<M> {
pub fn new(client: Arc<Mutex<Client>>, memory: Arc<M>) -> Self {
Self { client, memory }
}
}
impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMapping<M> {
fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error> {
let mem = self.memory.memory();
let guest_addr = GuestAddress(gpa);
let region = mem.find_region(guest_addr);
if let Some(region) = region {
let file_offset = region.file_offset().unwrap();
let offset = (GuestAddress(gpa).checked_offset_from(region.start_addr())).unwrap()
+ file_offset.start();
self.client
.lock()
.unwrap()
.dma_map(offset, iova, size, file_offset.file().as_raw_fd())
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error mapping region: {}", e),
)
})
} else {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Region not found for 0x{:x}", gpa),
));
}
}
fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error> {
self.client
.lock()
.unwrap()
.dma_unmap(iova, size)
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Error unmapping region: {}", e),
)
})
}
}

View File

@ -123,6 +123,8 @@ fn virtio_mem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_fallocate, vec![]),
(libc::SYS_ioctl, create_virtio_mem_ioctl_seccomp_rule()),
(libc::SYS_recvfrom, vec![]),
(libc::SYS_sendmsg, vec![]),
]
}

View File

@ -69,7 +69,7 @@ use libc::{
};
use pci::{
DeviceRelocation, PciBarRegionType, PciBus, PciConfigMmio, PciDevice, PciRoot, VfioPciDevice,
VfioUserPciDevice, VfioUserPciDeviceError,
VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError,
};
#[cfg(target_arch = "x86_64")]
use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
@ -3115,7 +3115,7 @@ impl DeviceManager {
let mut vfio_user_pci_device = VfioUserPciDevice::new(
&self.address_manager.vm,
client,
client.clone(),
&self.msi_interrupt_manager,
legacy_interrupt_group,
)
@ -3127,6 +3127,19 @@ impl DeviceManager {
})
.map_err(DeviceManagerError::VfioUserMapRegion)?;
let memory = self.memory_manager.lock().unwrap().guest_memory();
let vfio_user_mapping = Arc::new(VfioUserDmaMapping::new(client, Arc::new(memory)));
for virtio_mem_device in self.virtio_mem_devices.iter() {
virtio_mem_device
.lock()
.unwrap()
.add_dma_mapping_handler(
VirtioMemMappingSource::Device(pci_device_bdf),
vfio_user_mapping.clone(),
)
.map_err(DeviceManagerError::AddDmaMappingHandlerVirtioMem)?;
}
for (_, zone) in self.memory_manager.lock().unwrap().memory_zones().iter() {
for region in zone.regions() {
vfio_user_pci_device
@ -3564,6 +3577,7 @@ impl DeviceManager {
.pci_device_handle
.ok_or(DeviceManagerError::MissingPciDevice)?;
let (pci_device, bus_device, virtio_device) = match pci_device_handle {
// No need to remove any virtio-mem mapping here as the container outlives all devices
PciDeviceHandle::Vfio(vfio_pci_device) => (
Arc::clone(&vfio_pci_device) as Arc<Mutex<dyn PciDevice>>,
Arc::clone(&vfio_pci_device) as Arc<Mutex<dyn BusDevice>>,
@ -3594,6 +3608,14 @@ impl DeviceManager {
}
}
for virtio_mem_device in self.virtio_mem_devices.iter() {
virtio_mem_device
.lock()
.unwrap()
.remove_dma_mapping_handler(VirtioMemMappingSource::Device(pci_device_bdf))
.map_err(DeviceManagerError::RemoveDmaMappingHandlerVirtioMem)?;
}
(
Arc::clone(&vfio_user_pci_device) as Arc<Mutex<dyn PciDevice>>,
Arc::clone(&vfio_user_pci_device) as Arc<Mutex<dyn BusDevice>>,