diff --git a/crates/virtio-queue/src/iterator.rs b/crates/virtio-queue/src/iterator.rs index e3077445..fea7551e 100644 --- a/crates/virtio-queue/src/iterator.rs +++ b/crates/virtio-queue/src/iterator.rs @@ -102,7 +102,7 @@ pub struct AvailIter<'b, M> { impl<'b, M> AvailIter<'b, M> where M: Deref, - M::Target: GuestMemory + Sized, + M::Target: GuestMemory, { /// Create a new instance of `AvailInter`. /// diff --git a/crates/virtio-queue/src/lib.rs b/crates/virtio-queue/src/lib.rs index 5f5d4c44..9d13e289 100644 --- a/crates/virtio-queue/src/lib.rs +++ b/crates/virtio-queue/src/lib.rs @@ -155,7 +155,9 @@ pub trait QueueStateT: for<'a> QueueStateGuard<'a> { fn set_event_idx(&mut self, enabled: bool); /// Read the `idx` field from the available ring. - fn avail_idx(&self, mem: &M, order: Ordering) -> Result, Error>; + fn avail_idx(&self, mem: &M, order: Ordering) -> Result, Error> + where + M: GuestMemory + ?Sized; /// Read the `idx` field from the used ring. fn used_idx(&self, mem: &M, order: Ordering) -> Result, Error>; @@ -193,4 +195,14 @@ pub trait QueueStateT: for<'a> QueueStateGuard<'a> { /// Set the index for the next descriptor in the used ring. fn set_next_used(&mut self, next_used: u16); + + /// Pop and return the next available descriptor chain, or `None` when there are no more + /// descriptor chains available. + /// + /// This enables the consumption of available descriptor chains in a "one at a time" + /// manner, without having to hold a borrow after the method returns. + fn pop_descriptor_chain(&mut self, mem: M) -> Option> + where + M: Clone + Deref, + M::Target: GuestMemory; } diff --git a/crates/virtio-queue/src/state.rs b/crates/virtio-queue/src/state.rs index 3d65a1ff..40a8c11a 100644 --- a/crates/virtio-queue/src/state.rs +++ b/crates/virtio-queue/src/state.rs @@ -19,7 +19,10 @@ use crate::defs::{ VIRTQ_USED_ELEMENT_SIZE, VIRTQ_USED_F_NO_NOTIFY, VIRTQ_USED_RING_HEADER_SIZE, VIRTQ_USED_RING_META_SIZE, }; -use crate::{error, AvailIter, Descriptor, Error, QueueStateGuard, QueueStateT, VirtqUsedElem}; +use crate::{ + error, AvailIter, Descriptor, DescriptorChain, Error, QueueStateGuard, QueueStateT, + VirtqUsedElem, +}; /// Struct to maintain information and manipulate state of a virtio queue. /// @@ -71,7 +74,7 @@ impl QueueState { pub fn iter(&mut self, mem: M) -> Result, Error> where M: Deref, - M::Target: GuestMemory + Sized, + M::Target: GuestMemory, { self.avail_idx(mem.deref(), Ordering::Acquire) .map(move |idx| AvailIter::new(mem, idx, self)) @@ -311,7 +314,10 @@ impl QueueStateT for QueueState { self.event_idx_enabled = enabled; } - fn avail_idx(&self, mem: &M, order: Ordering) -> Result, Error> { + fn avail_idx(&self, mem: &M, order: Ordering) -> Result, Error> + where + M: GuestMemory + ?Sized, + { let addr = self .avail_ring .checked_add(2) @@ -450,4 +456,19 @@ impl QueueStateT for QueueState { fn set_next_used(&mut self, next_used: u16) { self.next_used = Wrapping(next_used); } + + fn pop_descriptor_chain(&mut self, mem: M) -> Option> + where + M: Clone + Deref, + M::Target: GuestMemory, + { + // Default, iter-based impl. Will be subsequently improved. + match self.iter(mem) { + Ok(mut iter) => iter.next(), + Err(e) => { + error!("Iterator error {}", e); + None + } + } + } } diff --git a/crates/virtio-queue/src/state_sync.rs b/crates/virtio-queue/src/state_sync.rs index f5c2aea1..42b4b91a 100644 --- a/crates/virtio-queue/src/state_sync.rs +++ b/crates/virtio-queue/src/state_sync.rs @@ -3,12 +3,13 @@ // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause use std::num::Wrapping; +use std::ops::Deref; use std::sync::atomic::Ordering; use std::sync::{Arc, Mutex, MutexGuard}; use vm_memory::GuestMemory; -use crate::{Error, QueueState, QueueStateGuard, QueueStateT}; +use crate::{DescriptorChain, Error, QueueState, QueueStateGuard, QueueStateT}; /// Struct to maintain information and manipulate state of a virtio queue for multi-threaded /// context. @@ -107,7 +108,10 @@ impl QueueStateT for QueueStateSync { self.lock_state().set_event_idx(enabled); } - fn avail_idx(&self, mem: &M, order: Ordering) -> Result, Error> { + fn avail_idx(&self, mem: &M, order: Ordering) -> Result, Error> + where + M: GuestMemory + ?Sized, + { self.lock_state().avail_idx(mem, order) } @@ -151,6 +155,14 @@ impl QueueStateT for QueueStateSync { fn set_next_used(&mut self, next_used: u16) { self.lock_state().set_next_used(next_used); } + + fn pop_descriptor_chain(&mut self, mem: M) -> Option> + where + M: Clone + Deref, + M::Target: GuestMemory, + { + self.lock_state().pop_descriptor_chain(mem) + } } #[cfg(test)]