From 3e750de43f6dd4800201ca3dff6a5855ebb75f2c Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Thu, 3 Oct 2019 17:04:02 -0700 Subject: [PATCH] vm-virtio: Implement reset() for virtio-pmem The virtio specification defines a device can be reset, which was not supported by this virtio-pmem implementation. The reason it is needed is to support unbinding this device from the guest driver, and rebind it to vfio-pci driver. Signed-off-by: Sebastien Boeuf --- vm-virtio/src/pmem.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/vm-virtio/src/pmem.rs b/vm-virtio/src/pmem.rs index e828b536b..c1f5cb93c 100644 --- a/vm-virtio/src/pmem.rs +++ b/vm-virtio/src/pmem.rs @@ -291,6 +291,8 @@ pub struct Pmem { avail_features: u64, acked_features: u64, config: VirtioPmemConfig, + queue_evts: Option>, + interrupt_cb: Option>, } impl Pmem { @@ -306,6 +308,8 @@ impl Pmem { avail_features: 1u64 << VIRTIO_F_VERSION_1, acked_features: 0u64, config, + queue_evts: None, + interrupt_cb: None, }) } } @@ -407,7 +411,26 @@ impl VirtioDevice for Pmem { }; self.kill_evt = Some(self_kill_evt); - if let Some(disk) = self.disk.take() { + // Save the interrupt EventFD as we need to return it on reset + // but clone it to pass into the thread. + self.interrupt_cb = Some(interrupt_cb.clone()); + + let mut tmp_queue_evts: Vec = Vec::new(); + for queue_evt in queue_evts.iter() { + // Save the queue EventFD as we need to return it on reset + // but clone it to pass into the thread. + tmp_queue_evts.push(queue_evt.try_clone().map_err(|e| { + error!("failed to clone queue EventFd: {}", e); + ActivateError::BadActivate + })?); + } + self.queue_evts = Some(tmp_queue_evts); + + if let Some(disk) = self.disk.as_ref() { + let disk = disk.try_clone().map_err(|e| { + error!("failed cloning pmem disk: {}", e); + ActivateError::BadActivate + })?; let mut handler = PmemEpollHandler { queue: queues.remove(0), mem, @@ -430,4 +453,17 @@ impl VirtioDevice for Pmem { } Err(ActivateError::BadActivate) } + + fn reset(&mut self) -> Option<(Arc, Vec)> { + if let Some(kill_evt) = self.kill_evt.take() { + // Ignore the result because there is nothing we can do about it. + let _ = kill_evt.write(1); + } + + // Return the interrupt and queue EventFDs + Some(( + self.interrupt_cb.take().unwrap(), + self.queue_evts.take().unwrap(), + )) + } }