virtio-devices: Pass a list of tuples for virtqueues

Instead of passing separately a list of Queues and the equivalent list
of EventFds, we consolidate these two through a tuple along with the
queue index.

The queue index can be very useful if looking for the actual index
related to the queue, no matter if other queues have been enabled or
not.

It's also convenient to have the EventFd associated with the Queue so
that we don't have to carry two lists with the same amount of items.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2022-07-20 16:45:49 +02:00
parent 423c54eafe
commit 3f62a172b2
20 changed files with 154 additions and 145 deletions

View File

@ -84,9 +84,8 @@ fuzz_target!(|bytes| {
q.state.ready = true; q.state.ready = true;
q.state.size = QUEUE_SIZE / 2; q.state.size = QUEUE_SIZE / 2;
let queue_evts: Vec<EventFd> = vec![EventFd::new(0).unwrap()]; let evt = EventFd::new(0).unwrap();
let queue_fd = queue_evts[0].as_raw_fd(); let queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(evt.as_raw_fd())) };
let queue_evt = unsafe { EventFd::from_raw_fd(libc::dup(queue_fd)) };
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap(); let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
let disk_file: File = unsafe { File::from_raw_fd(shm) }; let disk_file: File = unsafe { File::from_raw_fd(shm) };
@ -110,8 +109,7 @@ fuzz_target!(|bytes| {
.activate( .activate(
guest_memory, guest_memory,
Arc::new(NoopVirtioInterrupt {}), Arc::new(NoopVirtioInterrupt {}),
vec![q], vec![(0, q, evt)],
queue_evts,
) )
.ok(); .ok();

View File

@ -542,17 +542,23 @@ impl VirtioDevice for Balloon {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
let inflate_queue_evt = queue_evts.remove(0); let mut virtqueues = Vec::new();
let deflate_queue_evt = queue_evts.remove(0); let (_, queue, queue_evt) = queues.remove(0);
virtqueues.push(queue);
let inflate_queue_evt = queue_evt;
let (_, queue, queue_evt) = queues.remove(0);
virtqueues.push(queue);
let deflate_queue_evt = queue_evt;
let reporting_queue_evt = let reporting_queue_evt =
if self.common.feature_acked(VIRTIO_BALLOON_F_REPORTING) && !queue_evts.is_empty() { if self.common.feature_acked(VIRTIO_BALLOON_F_REPORTING) && !queues.is_empty() {
Some(queue_evts.remove(0)) let (_, queue, queue_evt) = queues.remove(0);
virtqueues.push(queue);
Some(queue_evt)
} else { } else {
None None
}; };
@ -563,7 +569,7 @@ impl VirtioDevice for Balloon {
error!("failed to clone resize EventFd: {:?}", e); error!("failed to clone resize EventFd: {:?}", e);
ActivateError::BadActivate ActivateError::BadActivate
})?, })?,
queues, queues: virtqueues,
interrupt_cb, interrupt_cb,
inflate_queue_evt, inflate_queue_evt,
deflate_queue_evt, deflate_queue_evt,

View File

@ -587,18 +587,16 @@ impl VirtioDevice for Block {
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let disk_image_id = build_disk_image_id(&self.disk_path); let disk_image_id = build_disk_image_id(&self.disk_path);
self.update_writeback(); self.update_writeback();
let mut epoll_threads = Vec::new(); let mut epoll_threads = Vec::new();
for i in 0..queues.len() { for i in 0..queues.len() {
let queue_evt = queue_evts.remove(0); let (_, queue, queue_evt) = queues.remove(0);
let queue = queues.remove(0);
let queue_size = queue.state.size; let queue_size = queue.state.size;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();

View File

@ -490,10 +490,9 @@ impl VirtioDevice for Console {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
self.resizer self.resizer
.acked_features .acked_features
.store(self.common.acked_features, Ordering::Relaxed); .store(self.common.acked_features, Ordering::Relaxed);
@ -507,13 +506,21 @@ impl VirtioDevice for Console {
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
let input_evt = EventFd::new(EFD_NONBLOCK).unwrap(); let input_evt = EventFd::new(EFD_NONBLOCK).unwrap();
let mut virtqueues = Vec::new();
let (_, queue, queue_evt) = queues.remove(0);
virtqueues.push(queue);
let input_queue_evt = queue_evt;
let (_, queue, queue_evt) = queues.remove(0);
virtqueues.push(queue);
let output_queue_evt = queue_evt;
let mut handler = ConsoleEpollHandler { let mut handler = ConsoleEpollHandler {
queues, queues: virtqueues,
interrupt_cb, interrupt_cb,
in_buffer: self.in_buffer.clone(), in_buffer: self.in_buffer.clone(),
endpoint: self.endpoint.clone(), endpoint: self.endpoint.clone(),
input_queue_evt: queue_evts.remove(0), input_queue_evt,
output_queue_evt: queue_evts.remove(0), output_queue_evt,
input_evt, input_evt,
config_evt: self.resizer.config_evt.try_clone().unwrap(), config_evt: self.resizer.config_evt.try_clone().unwrap(),
resize_pipe: self.resize_pipe.as_ref().map(|p| p.try_clone().unwrap()), resize_pipe: self.resize_pipe.as_ref().map(|p| p.try_clone().unwrap()),

View File

@ -107,8 +107,7 @@ pub trait VirtioDevice: Send {
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_evt: Arc<dyn VirtioInterrupt>, interrupt_evt: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
) -> ActivateResult; ) -> ActivateResult;
/// Optionally deactivates this device and returns ownership of the guest memory map, interrupt /// Optionally deactivates this device and returns ownership of the guest memory map, interrupt
@ -251,19 +250,9 @@ impl VirtioCommon {
pub fn activate( pub fn activate(
&mut self, &mut self,
queues: &[Queue<GuestMemoryAtomic<GuestMemoryMmap>>], queues: &[(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)],
queue_evts: &[EventFd],
interrupt_cb: &Arc<dyn VirtioInterrupt>, interrupt_cb: &Arc<dyn VirtioInterrupt>,
) -> ActivateResult { ) -> ActivateResult {
if queues.len() != queue_evts.len() {
error!(
"Cannot activate: length mismatch: queue_evts={} queues={}",
queue_evts.len(),
queues.len()
);
return Err(ActivateError::BadActivate);
}
if queues.len() < self.min_queues.into() { if queues.len() < self.min_queues.into() {
error!( error!(
"Number of enabled queues lower than min: {} vs {}", "Number of enabled queues lower than min: {} vs {}",
@ -290,7 +279,7 @@ impl VirtioCommon {
self.interrupt_cb = Some(interrupt_cb.clone()); self.interrupt_cb = Some(interrupt_cb.clone());
let mut tmp_queue_evts: Vec<EventFd> = Vec::new(); let mut tmp_queue_evts: Vec<EventFd> = Vec::new();
for queue_evt in queue_evts.iter() { for (_, _, queue_evt) in queues.iter() {
// Save the queue EventFD as we need to return it on reset // Save the queue EventFD as we need to return it on reset
// but clone it to pass into the thread. // but clone it to pass into the thread.
tmp_queue_evts.push(queue_evt.try_clone().map_err(|e| { tmp_queue_evts.push(queue_evt.try_clone().map_err(|e| {

View File

@ -1052,13 +1052,20 @@ impl VirtioDevice for Iommu {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
let mut virtqueues = Vec::new();
let mut queue_evts = Vec::new();
for (_, queue, queue_evt) in queues {
virtqueues.push(queue);
queue_evts.push(queue_evt);
}
let mut handler = IommuEpollHandler { let mut handler = IommuEpollHandler {
queues, queues: virtqueues,
interrupt_cb, interrupt_cb,
queue_evts, queue_evts,
kill_evt, kill_evt,

View File

@ -1004,20 +1004,22 @@ impl VirtioDevice for Mem {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
let (_, queue, queue_evt) = queues.remove(0);
let mut handler = MemEpollHandler { let mut handler = MemEpollHandler {
host_addr: self.host_addr, host_addr: self.host_addr,
host_fd: self.host_fd, host_fd: self.host_fd,
blocks_state: Arc::clone(&self.blocks_state), blocks_state: Arc::clone(&self.blocks_state),
config: self.config.clone(), config: self.config.clone(),
resize: self.resize.clone(), resize: self.resize.clone(),
queue: queues.remove(0), queue,
interrupt_cb, interrupt_cb,
queue_evt: queue_evts.remove(0), queue_evt,
kill_evt, kill_evt,
pause_evt, pause_evt,
hugepages: self.hugepages, hugepages: self.hugepages,

View File

@ -585,17 +585,15 @@ impl VirtioDevice for Net {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let num_queues = queues.len(); let num_queues = queues.len();
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into()); let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && num_queues % 2 != 0 { if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && num_queues % 2 != 0 {
let ctrl_queue_index = num_queues - 1; let ctrl_queue_index = num_queues - 1;
let mut ctrl_queue = queues.remove(ctrl_queue_index); let (_, mut ctrl_queue, ctrl_queue_evt) = queues.remove(ctrl_queue_index);
let ctrl_queue_evt = queue_evts.remove(ctrl_queue_index);
ctrl_queue.set_event_idx(event_idx); ctrl_queue.set_event_idx(event_idx);
@ -641,11 +639,13 @@ impl VirtioDevice for Net {
let tx = TxVirtio::new(); let tx = TxVirtio::new();
let rx_tap_listening = false; let rx_tap_listening = false;
let mut queue_pair = vec![queues.remove(0), queues.remove(0)]; let (_, queue_0, queue_evt_0) = queues.remove(0);
let (_, queue_1, queue_evt_1) = queues.remove(0);
let mut queue_pair = vec![queue_0, queue_1];
queue_pair[0].set_event_idx(event_idx); queue_pair[0].set_event_idx(event_idx);
queue_pair[1].set_event_idx(event_idx); queue_pair[1].set_event_idx(event_idx);
let queue_evt_pair = vec![queue_evts.remove(0), queue_evts.remove(0)]; let queue_evt_pair = vec![queue_evt_0, queue_evt_1];
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();

View File

@ -379,21 +379,23 @@ impl VirtioDevice for Pmem {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
if let Some(disk) = self.disk.as_ref() { if let Some(disk) = self.disk.as_ref() {
let disk = disk.try_clone().map_err(|e| { let disk = disk.try_clone().map_err(|e| {
error!("failed cloning pmem disk: {}", e); error!("failed cloning pmem disk: {}", e);
ActivateError::BadActivate ActivateError::BadActivate
})?; })?;
let (_, queue, queue_evt) = queues.remove(0);
let mut handler = PmemEpollHandler { let mut handler = PmemEpollHandler {
queue: queues.remove(0), queue,
disk, disk,
interrupt_cb, interrupt_cb,
queue_evt: queue_evts.remove(0), queue_evt,
kill_evt, kill_evt,
pause_evt, pause_evt,
access_platform: self.common.access_platform.clone(), access_platform: self.common.access_platform.clone(),

View File

@ -35,7 +35,7 @@ const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
const QUEUE_AVAIL_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1; const QUEUE_AVAIL_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
struct RngEpollHandler { struct RngEpollHandler {
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
random_file: File, random_file: File,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queue_evt: EventFd, queue_evt: EventFd,
@ -46,7 +46,7 @@ struct RngEpollHandler {
impl RngEpollHandler { impl RngEpollHandler {
fn process_queue(&mut self) -> bool { fn process_queue(&mut self) -> bool {
let queue = &mut self.queues[0]; let queue = &mut self.queue;
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize]; let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
let mut used_count = 0; let mut used_count = 0;
@ -219,10 +219,9 @@ impl VirtioDevice for Rng {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
if let Some(file) = self.random_file.as_ref() { if let Some(file) = self.random_file.as_ref() {
@ -230,11 +229,14 @@ impl VirtioDevice for Rng {
error!("failed cloning rng source: {}", e); error!("failed cloning rng source: {}", e);
ActivateError::BadActivate ActivateError::BadActivate
})?; })?;
let (_, queue, queue_evt) = queues.remove(0);
let mut handler = RngEpollHandler { let mut handler = RngEpollHandler {
queues, queue,
random_file, random_file,
interrupt_cb, interrupt_cb,
queue_evt: queue_evts.remove(0), queue_evt,
kill_evt, kill_evt,
pause_evt, pause_evt,
access_platform: self.common.access_platform.clone(), access_platform: self.common.access_platform.clone(),

View File

@ -385,8 +385,7 @@ mod tests {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
_interrupt_evt: Arc<dyn VirtioInterrupt>, _interrupt_evt: Arc<dyn VirtioInterrupt>,
_queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, _queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
_queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
Ok(()) Ok(())
} }

View File

@ -292,8 +292,8 @@ pub struct VirtioPciDeviceActivator {
memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>, memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
device: Arc<Mutex<dyn VirtioDevice>>, device: Arc<Mutex<dyn VirtioDevice>>,
device_activated: Arc<AtomicBool>, device_activated: Arc<AtomicBool>,
queues: Option<Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>>, #[allow(clippy::type_complexity)]
queue_evts: Option<Vec<EventFd>>, queues: Option<Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>>,
barrier: Option<Arc<Barrier>>, barrier: Option<Arc<Barrier>>,
id: String, id: String,
} }
@ -304,7 +304,6 @@ impl VirtioPciDeviceActivator {
self.memory.take().unwrap(), self.memory.take().unwrap(),
self.interrupt.take().unwrap(), self.interrupt.take().unwrap(),
self.queues.take().unwrap(), self.queues.take().unwrap(),
self.queue_evts.take().unwrap(),
)?; )?;
self.device_activated.store(true, Ordering::SeqCst); self.device_activated.store(true, Ordering::SeqCst);
@ -700,7 +699,6 @@ impl VirtioPciDevice {
fn prepare_activator(&mut self, barrier: Option<Arc<Barrier>>) -> VirtioPciDeviceActivator { fn prepare_activator(&mut self, barrier: Option<Arc<Barrier>>) -> VirtioPciDeviceActivator {
let mut queues = Vec::new(); let mut queues = Vec::new();
let mut queue_evts = Vec::new();
for (queue_index, queue) in self.queues.iter().enumerate() { for (queue_index, queue) in self.queues.iter().enumerate() {
if !queue.state.ready { if !queue.state.ready {
@ -711,8 +709,11 @@ impl VirtioPciDevice {
error!("Queue {} is not valid", queue_index); error!("Queue {} is not valid", queue_index);
} }
queues.push(vm_virtio::clone_queue(queue)); queues.push((
queue_evts.push(self.queue_evts[queue_index].try_clone().unwrap()); queue_index,
vm_virtio::clone_queue(queue),
self.queue_evts[queue_index].try_clone().unwrap(),
));
} }
VirtioPciDeviceActivator { VirtioPciDeviceActivator {
@ -721,7 +722,6 @@ impl VirtioPciDevice {
device: self.device.clone(), device: self.device.clone(),
queues: Some(queues), queues: Some(queues),
device_activated: self.device_activated.clone(), device_activated: self.device_activated.clone(),
queue_evts: Some(queue_evts),
barrier, barrier,
id: self.id.clone(), id: self.id.clone(),
} }

View File

@ -145,8 +145,7 @@ impl Vdpa {
&mut self, &mut self,
_mem: &GuestMemoryMmap, _mem: &GuestMemoryMmap,
virtio_interrupt: &Arc<dyn VirtioInterrupt>, virtio_interrupt: &Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
) -> Result<()> { ) -> Result<()> {
self.vhost self.vhost
.set_features(self.common.acked_features) .set_features(self.common.acked_features)
@ -155,11 +154,11 @@ impl Vdpa {
.set_backend_features(self.backend_features) .set_backend_features(self.backend_features)
.map_err(Error::SetBackendFeatures)?; .map_err(Error::SetBackendFeatures)?;
for (queue_index, queue) in queues.iter().enumerate() { for (queue_index, queue, queue_evt) in queues.iter() {
let queue_max_size = queue.max_size(); let queue_max_size = queue.max_size();
let queue_size = queue.state.size; let queue_size = queue.state.size;
self.vhost self.vhost
.set_vring_num(queue_index, queue_size) .set_vring_num(*queue_index, queue_size)
.map_err(Error::SetVringNum)?; .map_err(Error::SetVringNum)?;
let config_data = VringConfigData { let config_data = VringConfigData {
@ -194,11 +193,11 @@ impl Vdpa {
}; };
self.vhost self.vhost
.set_vring_addr(queue_index, &config_data) .set_vring_addr(*queue_index, &config_data)
.map_err(Error::SetVringAddr)?; .map_err(Error::SetVringAddr)?;
self.vhost self.vhost
.set_vring_base( .set_vring_base(
queue_index, *queue_index,
queue queue
.avail_idx(Ordering::Acquire) .avail_idx(Ordering::Acquire)
.map_err(Error::GetAvailableIndex)? .map_err(Error::GetAvailableIndex)?
@ -207,15 +206,15 @@ impl Vdpa {
.map_err(Error::SetVringBase)?; .map_err(Error::SetVringBase)?;
if let Some(eventfd) = if let Some(eventfd) =
virtio_interrupt.notifier(VirtioInterruptType::Queue(queue_index as u16)) virtio_interrupt.notifier(VirtioInterruptType::Queue(*queue_index as u16))
{ {
self.vhost self.vhost
.set_vring_call(queue_index, &eventfd) .set_vring_call(*queue_index, &eventfd)
.map_err(Error::SetVringCall)?; .map_err(Error::SetVringCall)?;
} }
self.vhost self.vhost
.set_vring_kick(queue_index, &queue_evts[queue_index]) .set_vring_kick(*queue_index, queue_evt)
.map_err(Error::SetVringKick)?; .map_err(Error::SetVringKick)?;
} }
@ -297,10 +296,9 @@ impl VirtioDevice for Vdpa {
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
virtio_interrupt: Arc<dyn VirtioInterrupt>, virtio_interrupt: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.activate_vdpa(&mem.memory(), &virtio_interrupt, queues, queue_evts) self.activate_vdpa(&mem.memory(), &virtio_interrupt, queues)
.map_err(ActivateError::ActivateVdpa)?; .map_err(ActivateError::ActivateVdpa)?;
// Store the virtio interrupt handler as we need to return it on reset // Store the virtio interrupt handler as we need to return it on reset

View File

@ -292,10 +292,9 @@ impl VirtioDevice for Blk {
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
self.guest_memory = Some(mem.clone()); self.guest_memory = Some(mem.clone());
let slave_req_handler: Option<MasterReqHandler<SlaveReqHandler>> = None; let slave_req_handler: Option<MasterReqHandler<SlaveReqHandler>> = None;
@ -307,7 +306,6 @@ impl VirtioDevice for Blk {
let mut handler = self.vu_common.activate( let mut handler = self.vu_common.activate(
mem, mem,
queues, queues,
queue_evts,
interrupt_cb, interrupt_cb,
self.common.acked_features, self.common.acked_features,
slave_req_handler, slave_req_handler,

View File

@ -504,10 +504,9 @@ impl VirtioDevice for Fs {
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
self.guest_memory = Some(mem.clone()); self.guest_memory = Some(mem.clone());
// Initialize slave communication. // Initialize slave communication.
@ -547,7 +546,6 @@ impl VirtioDevice for Fs {
let mut handler = self.vu_common.activate( let mut handler = self.vu_common.activate(
mem, mem,
queues, queues,
queue_evts,
interrupt_cb, interrupt_cb,
self.common.acked_features, self.common.acked_features,
slave_req_handler, slave_req_handler,

View File

@ -167,8 +167,7 @@ pub struct VhostUserEpollHandler<S: VhostUserMasterReqHandler> {
pub mem: GuestMemoryAtomic<GuestMemoryMmap>, pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
pub kill_evt: EventFd, pub kill_evt: EventFd,
pub pause_evt: EventFd, pub pause_evt: EventFd,
pub queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, pub queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
pub queue_evts: Vec<EventFd>,
pub virtio_interrupt: Arc<dyn VirtioInterrupt>, pub virtio_interrupt: Arc<dyn VirtioInterrupt>,
pub acked_features: u64, pub acked_features: u64,
pub acked_protocol_features: u64, pub acked_protocol_features: u64,
@ -224,10 +223,9 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
vhost_user vhost_user
.reinitialize_vhost_user( .reinitialize_vhost_user(
self.mem.memory().deref(), self.mem.memory().deref(),
self.queues.iter().map(vm_virtio::clone_queue).collect(), self.queues
self.queue_evts
.iter() .iter()
.map(|q| q.try_clone().unwrap()) .map(|(i, q, e)| (*i, vm_virtio::clone_queue(q), e.try_clone().unwrap()))
.collect(), .collect(),
&self.virtio_interrupt, &self.virtio_interrupt,
self.acked_features, self.acked_features,
@ -299,8 +297,7 @@ impl VhostUserCommon {
pub fn activate<T: VhostUserMasterReqHandler>( pub fn activate<T: VhostUserMasterReqHandler>(
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
acked_features: u64, acked_features: u64,
slave_req_handler: Option<MasterReqHandler<T>>, slave_req_handler: Option<MasterReqHandler<T>>,
@ -324,8 +321,10 @@ impl VhostUserCommon {
.unwrap() .unwrap()
.setup_vhost_user( .setup_vhost_user(
&mem.memory(), &mem.memory(),
queues.iter().map(vm_virtio::clone_queue).collect(), queues
queue_evts.iter().map(|q| q.try_clone().unwrap()).collect(), .iter()
.map(|(i, q, e)| (*i, vm_virtio::clone_queue(q), e.try_clone().unwrap()))
.collect(),
&interrupt_cb, &interrupt_cb,
acked_features, acked_features,
&slave_req_handler, &slave_req_handler,
@ -339,7 +338,6 @@ impl VhostUserCommon {
kill_evt, kill_evt,
pause_evt, pause_evt,
queues, queues,
queue_evts,
virtio_interrupt: interrupt_cb, virtio_interrupt: interrupt_cb,
acked_features, acked_features,
acked_protocol_features: self.acked_protocol_features, acked_protocol_features: self.acked_protocol_features,

View File

@ -272,18 +272,16 @@ impl VirtioDevice for Net {
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
mut queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
self.guest_memory = Some(mem.clone()); self.guest_memory = Some(mem.clone());
let num_queues = queues.len(); let num_queues = queues.len();
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into()); let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && num_queues % 2 != 0 { if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && num_queues % 2 != 0 {
let ctrl_queue_index = num_queues - 1; let ctrl_queue_index = num_queues - 1;
let mut ctrl_queue = queues.remove(ctrl_queue_index); let (_, mut ctrl_queue, ctrl_queue_evt) = queues.remove(ctrl_queue_index);
let ctrl_queue_evt = queue_evts.remove(ctrl_queue_index);
ctrl_queue.set_event_idx(event_idx); ctrl_queue.set_event_idx(event_idx);
@ -336,7 +334,6 @@ impl VirtioDevice for Net {
let mut handler = self.vu_common.activate( let mut handler = self.vu_common.activate(
mem, mem,
queues, queues,
queue_evts,
interrupt_cb, interrupt_cb,
backend_acked_features, backend_acked_features,
slave_req_handler, slave_req_handler,

View File

@ -151,8 +151,7 @@ impl VhostUserHandle {
pub fn setup_vhost_user<S: VhostUserMasterReqHandler>( pub fn setup_vhost_user<S: VhostUserMasterReqHandler>(
&mut self, &mut self,
mem: &GuestMemoryMmap, mem: &GuestMemoryMmap,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
virtio_interrupt: &Arc<dyn VirtioInterrupt>, virtio_interrupt: &Arc<dyn VirtioInterrupt>,
acked_features: u64, acked_features: u64,
slave_req_handler: &Option<MasterReqHandler<S>>, slave_req_handler: &Option<MasterReqHandler<S>>,
@ -171,9 +170,9 @@ impl VhostUserHandle {
// Send set_vring_num here, since it could tell backends, like SPDK, // Send set_vring_num here, since it could tell backends, like SPDK,
// how many virt queues to be handled, which backend required to know // how many virt queues to be handled, which backend required to know
// at early stage. // at early stage.
for (queue_index, queue) in queues.iter().enumerate() { for (queue_index, queue, _) in queues.iter() {
self.vu self.vu
.set_vring_num(queue_index, queue.state.size) .set_vring_num(*queue_index, queue.state.size)
.map_err(Error::VhostUserSetVringNum)?; .map_err(Error::VhostUserSetVringNum)?;
} }
@ -184,7 +183,7 @@ impl VhostUserHandle {
mmap_size: 0, mmap_size: 0,
mmap_offset: 0, mmap_offset: 0,
num_queues: queues.len() as u16, num_queues: queues.len() as u16,
queue_size: queues[0].state.size, queue_size: queues[0].1.state.size,
}; };
let (info, fd) = self let (info, fd) = self
.vu .vu
@ -202,7 +201,7 @@ impl VhostUserHandle {
let num_queues = queues.len() as usize; let num_queues = queues.len() as usize;
let mut vrings_info = Vec::new(); let mut vrings_info = Vec::new();
for (queue_index, queue) in queues.into_iter().enumerate() { for (queue_index, queue, queue_evt) in queues.iter() {
let actual_size: usize = queue.state.size.try_into().unwrap(); let actual_size: usize = queue.state.size.try_into().unwrap();
let config_data = VringConfigData { let config_data = VringConfigData {
@ -240,11 +239,11 @@ impl VhostUserHandle {
}); });
self.vu self.vu
.set_vring_addr(queue_index, &config_data) .set_vring_addr(*queue_index, &config_data)
.map_err(Error::VhostUserSetVringAddr)?; .map_err(Error::VhostUserSetVringAddr)?;
self.vu self.vu
.set_vring_base( .set_vring_base(
queue_index, *queue_index,
queue queue
.avail_idx(Ordering::Acquire) .avail_idx(Ordering::Acquire)
.map_err(Error::GetAvailableIndex)? .map_err(Error::GetAvailableIndex)?
@ -253,15 +252,15 @@ impl VhostUserHandle {
.map_err(Error::VhostUserSetVringBase)?; .map_err(Error::VhostUserSetVringBase)?;
if let Some(eventfd) = if let Some(eventfd) =
virtio_interrupt.notifier(VirtioInterruptType::Queue(queue_index as u16)) virtio_interrupt.notifier(VirtioInterruptType::Queue(*queue_index as u16))
{ {
self.vu self.vu
.set_vring_call(queue_index, &eventfd) .set_vring_call(*queue_index, &eventfd)
.map_err(Error::VhostUserSetVringCall)?; .map_err(Error::VhostUserSetVringCall)?;
} }
self.vu self.vu
.set_vring_kick(queue_index, &queue_evts[queue_index]) .set_vring_kick(*queue_index, queue_evt)
.map_err(Error::VhostUserSetVringKick)?; .map_err(Error::VhostUserSetVringKick)?;
} }
@ -326,8 +325,7 @@ impl VhostUserHandle {
pub fn reinitialize_vhost_user<S: VhostUserMasterReqHandler>( pub fn reinitialize_vhost_user<S: VhostUserMasterReqHandler>(
&mut self, &mut self,
mem: &GuestMemoryMmap, mem: &GuestMemoryMmap,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
virtio_interrupt: &Arc<dyn VirtioInterrupt>, virtio_interrupt: &Arc<dyn VirtioInterrupt>,
acked_features: u64, acked_features: u64,
acked_protocol_features: u64, acked_protocol_features: u64,
@ -339,7 +337,6 @@ impl VhostUserHandle {
self.setup_vhost_user( self.setup_vhost_user(
mem, mem,
queues, queues,
queue_evts,
virtio_interrupt, virtio_interrupt,
acked_features, acked_features,
slave_req_handler, slave_req_handler,

View File

@ -432,15 +432,21 @@ where
&mut self, &mut self,
mem: GuestMemoryAtomic<GuestMemoryMmap>, mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
let mut virtqueues = Vec::new();
let mut queue_evts = Vec::new();
for (_, queue, queue_evt) in queues {
virtqueues.push(queue);
queue_evts.push(queue_evt);
}
let mut handler = VsockEpollHandler { let mut handler = VsockEpollHandler {
mem, mem,
queues, queues: virtqueues,
queue_evts, queue_evts,
kill_evt, kill_evt,
pause_evt, pause_evt,
@ -591,7 +597,6 @@ mod tests {
GuestMemoryAtomic::new(ctx.mem.clone()), GuestMemoryAtomic::new(ctx.mem.clone()),
Arc::new(NoopVirtioInterrupt {}), Arc::new(NoopVirtioInterrupt {}),
Vec::new(), Vec::new(),
Vec::new(),
); );
match bad_activate { match bad_activate {
Err(ActivateError::BadActivate) => (), Err(ActivateError::BadActivate) => (),
@ -606,14 +611,21 @@ mod tests {
memory.clone(), memory.clone(),
Arc::new(NoopVirtioInterrupt {}), Arc::new(NoopVirtioInterrupt {}),
vec![ vec![
(
0,
Queue::new(memory.clone(), 256), Queue::new(memory.clone(), 256),
EventFd::new(EFD_NONBLOCK).unwrap(),
),
(
1,
Queue::new(memory.clone(), 256), Queue::new(memory.clone(), 256),
EventFd::new(EFD_NONBLOCK).unwrap(),
),
(
2,
Queue::new(memory, 256), Queue::new(memory, 256),
],
vec![
EventFd::new(EFD_NONBLOCK).unwrap(),
EventFd::new(EFD_NONBLOCK).unwrap(),
EventFd::new(EFD_NONBLOCK).unwrap(), EventFd::new(EFD_NONBLOCK).unwrap(),
),
], ],
) )
.unwrap(); .unwrap();

View File

@ -47,7 +47,7 @@ const WATCHDOG_TIMER_INTERVAL: i64 = 15;
const WATCHDOG_TIMEOUT: u64 = WATCHDOG_TIMER_INTERVAL as u64 + 5; const WATCHDOG_TIMEOUT: u64 = WATCHDOG_TIMER_INTERVAL as u64 + 5;
struct WatchdogEpollHandler { struct WatchdogEpollHandler {
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queue_evt: EventFd, queue_evt: EventFd,
kill_evt: EventFd, kill_evt: EventFd,
@ -61,7 +61,7 @@ impl WatchdogEpollHandler {
// The main queue is very simple - the driver "pings" the device by passing it a (write-only) // The main queue is very simple - the driver "pings" the device by passing it a (write-only)
// descriptor. In response the device writes a 1 into the descriptor and returns it to the driver // descriptor. In response the device writes a 1 into the descriptor and returns it to the driver
fn process_queue(&mut self) -> bool { fn process_queue(&mut self) -> bool {
let queue = &mut self.queues[0]; let queue = &mut self.queue;
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize]; let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
let mut used_count = 0; let mut used_count = 0;
for mut desc_chain in queue.iter().unwrap() { for mut desc_chain in queue.iter().unwrap() {
@ -291,10 +291,9 @@ impl VirtioDevice for Watchdog {
&mut self, &mut self,
_mem: GuestMemoryAtomic<GuestMemoryMmap>, _mem: GuestMemoryAtomic<GuestMemoryMmap>,
interrupt_cb: Arc<dyn VirtioInterrupt>, interrupt_cb: Arc<dyn VirtioInterrupt>,
queues: Vec<Queue<GuestMemoryAtomic<GuestMemoryMmap>>>, mut queues: Vec<(usize, Queue<GuestMemoryAtomic<GuestMemoryMmap>>, EventFd)>,
mut queue_evts: Vec<EventFd>,
) -> ActivateResult { ) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?; self.common.activate(&queues, &interrupt_cb)?;
let (kill_evt, pause_evt) = self.common.dup_eventfds(); let (kill_evt, pause_evt) = self.common.dup_eventfds();
let reset_evt = self.reset_evt.try_clone().map_err(|e| { let reset_evt = self.reset_evt.try_clone().map_err(|e| {
@ -307,10 +306,12 @@ impl VirtioDevice for Watchdog {
ActivateError::BadActivate ActivateError::BadActivate
})?; })?;
let (_, queue, queue_evt) = queues.remove(0);
let mut handler = WatchdogEpollHandler { let mut handler = WatchdogEpollHandler {
queues, queue,
interrupt_cb, interrupt_cb,
queue_evt: queue_evts.remove(0), queue_evt,
kill_evt, kill_evt,
pause_evt, pause_evt,
timer, timer,