vfio: Create a global KVM VFIO device for all VFIO devices

KVM does not support multiple KVM VFIO devices to be created when
trying to support multiple VFIO devices. This commit creates one
global KVM VFIO device being shared with every VFIO device, which
makes possible the support for passing several devices through the
VM.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-07-24 21:15:46 -07:00 committed by Rob Bradford
parent 0ff074d2b8
commit b5eab43aa5
2 changed files with 28 additions and 25 deletions

View File

@ -36,7 +36,6 @@ pub enum VfioError {
UnsetContainer, UnsetContainer,
ContainerSetIOMMU, ContainerSetIOMMU,
GroupGetDeviceFD, GroupGetDeviceFD,
CreateVfioKvmDevice(io::Error),
KvmSetDeviceAttr(io::Error), KvmSetDeviceAttr(io::Error),
VfioDeviceGetInfo, VfioDeviceGetInfo,
VfioDeviceGetRegionInfo, VfioDeviceGetRegionInfo,
@ -77,9 +76,6 @@ impl fmt::Display for VfioError {
"failed to set container's IOMMU driver type as VfioType1V2" "failed to set container's IOMMU driver type as VfioType1V2"
), ),
VfioError::GroupGetDeviceFD => write!(f, "failed to get vfio device fd"), VfioError::GroupGetDeviceFD => write!(f, "failed to get vfio device fd"),
VfioError::CreateVfioKvmDevice(e) => {
write!(f, "failed to create KVM vfio device: {}", e)
}
VfioError::KvmSetDeviceAttr(e) => { VfioError::KvmSetDeviceAttr(e) => {
write!(f, "failed to set KVM vfio device's attribute: {}", e) write!(f, "failed to set KVM vfio device's attribute: {}", e)
} }
@ -201,12 +197,12 @@ impl AsRawFd for VfioContainer {
struct VfioGroup { struct VfioGroup {
group: File, group: File,
device: DeviceFd, device: Arc<DeviceFd>,
container: VfioContainer, container: VfioContainer,
} }
impl VfioGroup { impl VfioGroup {
fn new(id: u32, vm: &Arc<VmFd>) -> Result<Self> { fn new(id: u32, device: Arc<DeviceFd>) -> Result<Self> {
let group_path = Path::new("/dev/vfio").join(id.to_string()); let group_path = Path::new("/dev/vfio").join(id.to_string());
let group = OpenOptions::new() let group = OpenOptions::new()
.read(true) .read(true)
@ -246,7 +242,7 @@ impl VfioGroup {
container.set_iommu(VFIO_TYPE1v2_IOMMU)?; container.set_iommu(VFIO_TYPE1v2_IOMMU)?;
let device = Self::kvm_device_add_group(vm, &group)?; Self::kvm_device_add_group(&device, &group)?;
Ok(VfioGroup { Ok(VfioGroup {
group, group,
@ -255,17 +251,7 @@ impl VfioGroup {
}) })
} }
fn kvm_device_add_group(vm: &VmFd, group: &File) -> Result<DeviceFd> { fn kvm_device_add_group(device_fd: &Arc<DeviceFd>, group: &File) -> Result<()> {
let mut vfio_dev = kvm_bindings::kvm_create_device {
type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_VFIO,
fd: 0,
flags: 0,
};
let device_fd = vm
.create_device(&mut vfio_dev)
.map_err(VfioError::CreateVfioKvmDevice)?;
let group_fd = group.as_raw_fd(); let group_fd = group.as_raw_fd();
let group_fd_ptr = &group_fd as *const i32; let group_fd_ptr = &group_fd as *const i32;
let dev_attr = kvm_bindings::kvm_device_attr { let dev_attr = kvm_bindings::kvm_device_attr {
@ -277,9 +263,7 @@ impl VfioGroup {
device_fd device_fd
.set_device_attr(&dev_attr) .set_device_attr(&dev_attr)
.map_err(VfioError::KvmSetDeviceAttr)?; .map_err(VfioError::KvmSetDeviceAttr)
Ok(device_fd)
} }
fn kvm_device_del_group(&self) -> std::result::Result<(), io::Error> { fn kvm_device_del_group(&self) -> std::result::Result<(), io::Error> {
@ -536,7 +520,7 @@ impl VfioDevice {
/// Create a new vfio device, then guest read/write on this device could be /// Create a new vfio device, then guest read/write on this device could be
/// transfered into kernel vfio. /// transfered into kernel vfio.
/// sysfspath specify the vfio device path in sys file system. /// sysfspath specify the vfio device path in sys file system.
pub fn new(sysfspath: &Path, vm: &Arc<VmFd>, mem: GuestMemoryMmap) -> Result<Self> { pub fn new(sysfspath: &Path, device_fd: Arc<DeviceFd>, mem: GuestMemoryMmap) -> Result<Self> {
let uuid_path: PathBuf = [sysfspath, Path::new("iommu_group")].iter().collect(); let uuid_path: PathBuf = [sysfspath, Path::new("iommu_group")].iter().collect();
let group_path = uuid_path.read_link().map_err(|_| VfioError::InvalidPath)?; let group_path = uuid_path.read_link().map_err(|_| VfioError::InvalidPath)?;
let group_osstr = group_path.file_name().ok_or(VfioError::InvalidPath)?; let group_osstr = group_path.file_name().ok_or(VfioError::InvalidPath)?;
@ -545,7 +529,7 @@ impl VfioDevice {
.parse::<u32>() .parse::<u32>()
.map_err(|_| VfioError::InvalidPath)?; .map_err(|_| VfioError::InvalidPath)?;
let group = VfioGroup::new(group_id, vm)?; let group = VfioGroup::new(group_id, device_fd)?;
let device_info = group.get_device(sysfspath)?; let device_info = group.get_device(sysfspath)?;
let regions = device_info.get_regions()?; let regions = device_info.get_regions()?;
let irqs = device_info.get_irqs()?; let irqs = device_info.get_irqs()?;

View File

@ -256,6 +256,9 @@ pub enum DeviceManagerError {
/// Failed to map VFIO MMIO region. /// Failed to map VFIO MMIO region.
VfioMapRegion(VfioPciError), VfioMapRegion(VfioPciError),
/// Failed to create the KVM device.
CreateKvmDevice(io::Error),
} }
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>; pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
@ -946,6 +949,17 @@ impl DeviceManager {
Ok(()) Ok(())
} }
fn create_kvm_device(vm: &Arc<VmFd>) -> DeviceManagerResult<DeviceFd> {
let mut vfio_dev = kvm_bindings::kvm_create_device {
type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_VFIO,
fd: 0,
flags: 0,
};
vm.create_device(&mut vfio_dev)
.map_err(DeviceManagerError::CreateKvmDevice)
}
fn add_vfio_devices( fn add_vfio_devices(
memory: GuestMemoryMmap, memory: GuestMemoryMmap,
allocator: &mut SystemAllocator, allocator: &mut SystemAllocator,
@ -956,9 +970,14 @@ impl DeviceManager {
mem_slots: u32, mem_slots: u32,
) -> DeviceManagerResult<()> { ) -> DeviceManagerResult<()> {
if let Some(device_list_cfg) = &vm_cfg.devices { if let Some(device_list_cfg) = &vm_cfg.devices {
// Create the KVM VFIO device
let device_fd = DeviceManager::create_kvm_device(vm_fd)?;
let device_fd = Arc::new(device_fd);
for device_cfg in device_list_cfg.iter() { for device_cfg in device_list_cfg.iter() {
let vfio_device = VfioDevice::new(device_cfg.path, vm_fd, memory.clone()) let vfio_device =
.map_err(DeviceManagerError::VfioCreate)?; VfioDevice::new(device_cfg.path, device_fd.clone(), memory.clone())
.map_err(DeviceManagerError::VfioCreate)?;
let mut vfio_pci_device = VfioPciDevice::new(vm_fd, allocator, vfio_device) let mut vfio_pci_device = VfioPciDevice::new(vm_fd, allocator, vfio_device)
.map_err(DeviceManagerError::VfioPciCreate)?; .map_err(DeviceManagerError::VfioPciCreate)?;