From 4115fa8a879878d6e25f71fc5e602b112b154fbe Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 26 Nov 2019 15:57:55 -0800 Subject: [PATCH] vfio: pci: Update irqfd registration In order to improve the existing VFIO code, this patch registers the eventfds used to trigger KVM interrupts only when the interrupts are enabled, and unregisters them when interrupts are disabled. Signed-off-by: Sebastien Boeuf --- vfio/src/vfio_pci.rs | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 558d33b29..90d46e463 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -236,19 +236,26 @@ struct InterruptRoute { } impl InterruptRoute { - fn new(vm: &Arc, allocator: &mut SystemAllocator, msi_vector: MsiVector) -> Result { + fn new(allocator: &mut SystemAllocator, msi_vector: MsiVector) -> Result { let irq_fd = EventFd::new(libc::EFD_NONBLOCK).map_err(VfioPciError::EventFd)?; let gsi = allocator.allocate_gsi().ok_or(VfioPciError::AllocateGsi)?; - vm.register_irqfd(&irq_fd, gsi) - .map_err(VfioPciError::IrqFd)?; - Ok(InterruptRoute { gsi, irq_fd, msi_vector, }) } + + fn enable(&self, vm: &Arc) -> Result<()> { + vm.register_irqfd(&self.irq_fd, self.gsi) + .map_err(VfioPciError::IrqFd) + } + + fn disable(&self, vm: &Arc) -> Result<()> { + vm.unregister_irqfd(&self.irq_fd, self.gsi) + .map_err(VfioPciError::IrqFd) + } } #[derive(Copy, Clone)] @@ -361,23 +368,32 @@ impl VfioPciDevice { let max_interrupts = vfio_pci_device.device.max_interrupts(); for _ in 0..max_interrupts { let msi_vector: MsiVector = Default::default(); - let route = InterruptRoute::new(vm_fd, allocator, msi_vector)?; + let route = InterruptRoute::new(allocator, msi_vector)?; vfio_pci_device.interrupt_routes.push(route); } Ok(vfio_pci_device) } - fn irq_fds(&self) -> Result> { + fn enable_irq_fds(&self) -> Result> { let mut irq_fds: Vec<&EventFd> = Vec::new(); for r in &self.interrupt_routes { + r.enable(&self.vm_fd)?; irq_fds.push(&r.irq_fd); } Ok(irq_fds) } + fn disable_irq_fds(&self) -> Result<()> { + for r in &self.interrupt_routes { + r.disable(&self.vm_fd)?; + } + + Ok(()) + } + fn set_kvm_routes(&self) -> Result<()> { let mut entry_vec: Vec = Vec::new(); for route in self.interrupt_routes.iter() { @@ -535,7 +551,7 @@ impl VfioPciDevice { fn update_msi_capabilities(&mut self, offset: u64, data: &[u8]) -> Result<()> { match self.interrupt.update_msi(offset, data) { - Some(InterruptUpdateAction::EnableMsi) => match self.irq_fds() { + Some(InterruptUpdateAction::EnableMsi) => match self.enable_irq_fds() { Ok(fds) => { if let Err(e) = self.device.enable_msi(fds) { warn!("Could not enable MSI: {}", e); @@ -544,6 +560,9 @@ impl VfioPciDevice { Err(e) => warn!("Could not get IRQ fds: {}", e), }, Some(InterruptUpdateAction::DisableMsi) => { + if let Err(e) = self.disable_irq_fds() { + warn!("Could not disable MSI: {}", e); + } if let Err(e) = self.device.disable_msi() { warn!("Could not disable MSI: {}", e); } @@ -564,7 +583,7 @@ impl VfioPciDevice { fn update_msix_capabilities(&mut self, offset: u64, data: &[u8]) { match self.interrupt.update_msix(offset, data) { - Some(InterruptUpdateAction::EnableMsix) => match self.irq_fds() { + Some(InterruptUpdateAction::EnableMsix) => match self.enable_irq_fds() { Ok(fds) => { if let Err(e) = self.device.enable_msix(fds) { warn!("Could not enable MSI-X: {}", e); @@ -573,6 +592,9 @@ impl VfioPciDevice { Err(e) => warn!("Could not get IRQ fds: {}", e), }, Some(InterruptUpdateAction::DisableMsix) => { + if let Err(e) = self.disable_irq_fds() { + warn!("Could not disable MSI: {}", e); + } if let Err(e) = self.device.disable_msix() { warn!("Could not disable MSI-X: {}", e); }