devices: vfio: create KVM_DEV_TYPE_VFIO device from linux.rs

One KVM_DEV_TYPE_VFIO instance may be created per VM.  Currently this
device is created from VfioContainer::init(), which makes it not able
to create multiple vfio container.

This patch creates the KVM_DEV_TYPE_VFIO virtual device before creating
any VfioContainer or VfioDevice instances, and passes it into the
VfioDevice constructor where it's actually used.  In this way, it's
possible to create multiple VFIO containers

BUG=b:181736020
TEST=passthru multiple devices and create more than one VFIO containers

Change-Id: I4b4e4941363efa91f2217af385f4f00eadd041c5
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2976053
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: David Stevens <stevensd@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: David Stevens <stevensd@chromium.org>
This commit is contained in:
Zide Chen 2021-04-19 11:06:01 -07:00 committed by Commit Bot
parent f7979867d6
commit 5deee48856
2 changed files with 30 additions and 25 deletions

View file

@ -19,7 +19,6 @@ use base::{
ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val, warn,
AsRawDescriptor, Error, Event, FromRawDescriptor, RawDescriptor, SafeDescriptor,
};
use hypervisor::{DeviceKind, Vm};
use vm_memory::GuestMemory;
use vfio_sys::*;
@ -35,7 +34,6 @@ pub enum VfioError {
GroupSetContainer(Error),
ContainerSetIOMMU(Error),
GroupGetDeviceFD(Error),
CreateVfioKvmDevice(Error),
KvmSetDeviceAttr(Error),
VfioDeviceGetInfo(Error),
VfioDeviceGetRegionInfo(Error),
@ -60,7 +58,6 @@ impl fmt::Display for VfioError {
VfioError::GroupSetContainer(e) => write!(f, "failed to add vfio group into vfio container: {}", e),
VfioError::ContainerSetIOMMU(e) => write!(f, "failed to set container's IOMMU driver type as VfioType1V2: {}", e),
VfioError::GroupGetDeviceFD(e) => write!(f, "failed to get vfio device fd: {}", e),
VfioError::CreateVfioKvmDevice(e) => write!(f, "failed to create KVM vfio device: {}", e),
VfioError::KvmSetDeviceAttr(e) => write!(f, "failed to set KVM vfio device's attribute: {}", e),
VfioError::VfioDeviceGetInfo(e) => write!(f, "failed to get vfio device's info or info doesn't match: {}", e),
VfioError::VfioDeviceGetRegionInfo(e) => write!(f, "failed to get vfio device's region info: {}", e),
@ -82,7 +79,6 @@ fn get_error() -> Error {
/// VfioContainer contain multi VfioGroup, and delegate an IOMMU domain table
pub struct VfioContainer {
container: File,
kvm_vfio_dev: Option<SafeDescriptor>,
groups: HashMap<u32, Arc<VfioGroup>>,
}
@ -104,7 +100,6 @@ impl VfioContainer {
Ok(VfioContainer {
container,
kvm_vfio_dev: None,
groups: HashMap::new(),
})
}
@ -163,7 +158,7 @@ impl VfioContainer {
Ok(())
}
fn init(&mut self, vm: &impl Vm, guest_mem: &GuestMemory) -> Result<(), VfioError> {
fn init(&mut self, guest_mem: &GuestMemory) -> Result<(), VfioError> {
if !self.check_extension(VFIO_TYPE1v2_IOMMU) {
return Err(VfioError::VfioType1V2);
}
@ -179,19 +174,14 @@ impl VfioContainer {
unsafe { self.vfio_dma_map(guest_addr.0, size as u64, host_addr as u64) }
})?;
let vfio_descriptor = vm
.create_device(DeviceKind::Vfio)
.map_err(VfioError::CreateVfioKvmDevice)?;
self.kvm_vfio_dev = Some(vfio_descriptor);
Ok(())
}
fn get_group(
&mut self,
id: u32,
vm: &impl Vm,
guest_mem: &GuestMemory,
kvm_vfio_file: &SafeDescriptor,
) -> Result<Arc<VfioGroup>, VfioError> {
match self.groups.get(&id) {
Some(group) => Ok(group.clone()),
@ -201,13 +191,9 @@ impl VfioContainer {
if self.groups.is_empty() {
// Before the first group is added into container, do once cotainer
// initialize for a vm
self.init(vm, guest_mem)?;
self.init(guest_mem)?;
}
let kvm_vfio_file = self
.kvm_vfio_dev
.as_ref()
.expect("kvm vfio device should exist");
group.kvm_device_add_group(kvm_vfio_file)?;
self.groups.insert(id, group.clone());
@ -351,10 +337,12 @@ impl VfioDevice {
/// Create a new vfio device, then guest read/write on this device could be
/// transfered into kernel vfio.
/// sysfspath specify the vfio device path in sys file system.
/// kvm_vfio_file specify a valid file descriptor returned from KVM_CREATE_DEVICE
/// with type KVM_DEV_TYPE_VFIO
pub fn new(
sysfspath: &Path,
vm: &impl Vm,
guest_mem: &GuestMemory,
kvm_vfio_file: &SafeDescriptor,
container: Arc<Mutex<VfioContainer>>,
) -> Result<Self, VfioError> {
let mut uuid_path = PathBuf::new();
@ -367,7 +355,9 @@ impl VfioDevice {
.parse::<u32>()
.map_err(|_| VfioError::InvalidPath)?;
let group = container.lock().get_group(group_id, vm, guest_mem)?;
let group = container
.lock()
.get_group(group_id, guest_mem, kvm_vfio_file)?;
let name_osstr = sysfspath.file_name().ok_or(VfioError::InvalidPath)?;
let name_str = name_osstr.to_str().ok_or(VfioError::InvalidPath)?;
let name = String::from(name_str);

View file

@ -51,7 +51,7 @@ use devices::{
#[cfg(feature = "usb")]
use devices::{HostBackendDeviceProvider, XhciController};
use hypervisor::kvm::{Kvm, KvmVcpu, KvmVm};
use hypervisor::{HypervisorCap, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap};
use hypervisor::{DeviceKind, HypervisorCap, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap};
use minijail::{self, Minijail};
use net_util::{Error as NetError, MacAddress, Tap};
use remain::sorted;
@ -124,6 +124,7 @@ pub enum Error {
CreateUsbProvider(devices::usb::host_backend::error::Error),
CreateVcpu(base::Error),
CreateVfioDevice(devices::vfio::VfioError),
CreateVfioKvmDevice(base::Error),
CreateVm(base::Error),
CreateWaitContext(base::Error),
DeviceJail(minijail::Error),
@ -253,6 +254,7 @@ impl Display for Error {
CreateUsbProvider(e) => write!(f, "failed to create usb provider: {}", e),
CreateVcpu(e) => write!(f, "failed to create vcpu: {}", e),
CreateVfioDevice(e) => write!(f, "Failed to create vfio device {}", e),
CreateVfioKvmDevice(e) => write!(f, "failed to create KVM vfio device: {}", e),
CreateVm(e) => write!(f, "failed to create vm: {}", e),
CreateWaitContext(e) => write!(f, "failed to create wait context: {}", e),
DeviceJail(e) => write!(f, "failed to jail device: {}", e),
@ -1735,6 +1737,7 @@ fn create_vfio_device(
resources: &mut SystemAllocator,
control_tubes: &mut Vec<TaggedControlTube>,
vfio_path: &Path,
kvm_vfio_file: &SafeDescriptor,
) -> DeviceResult<(Box<VfioPciDevice>, Option<Minijail>)> {
let vfio_container =
VFIO_CONTAINER.with::<_, DeviceResult<Arc<Mutex<VfioContainer>>>>(|v| {
@ -1763,7 +1766,7 @@ fn create_vfio_device(
let (vfio_host_tube_mem, vfio_device_tube_mem) = Tube::pair().map_err(Error::CreateTube)?;
control_tubes.push(TaggedControlTube::VmMemory(vfio_host_tube_mem));
let vfio_device = VfioDevice::new(vfio_path, vm, vm.get_memory(), vfio_container)
let vfio_device = VfioDevice::new(vfio_path, vm.get_memory(), &kvm_vfio_file, vfio_container)
.map_err(Error::CreateVfioDevice)?;
let mut vfio_pci_device = Box::new(VfioPciDevice::new(
vfio_device,
@ -1837,10 +1840,22 @@ fn create_devices(
pci_devices.push((usb_controller, simple_jail(&cfg, "xhci")?));
}
for vfio_path in &cfg.vfio {
let (vfio_pci_device, jail) =
create_vfio_device(cfg, vm, resources, control_tubes, vfio_path.as_path())?;
pci_devices.push((vfio_pci_device, jail));
if !cfg.vfio.is_empty() {
let kvm_vfio_file = vm
.create_device(DeviceKind::Vfio)
.map_err(Error::CreateVfioKvmDevice)?;
for vfio_path in &cfg.vfio {
let (vfio_pci_device, jail) = create_vfio_device(
cfg,
vm,
resources,
control_tubes,
vfio_path.as_path(),
&kvm_vfio_file,
)?;
pci_devices.push((vfio_pci_device, jail));
}
}
Ok(pci_devices)