Skip to content

Commit fae1928

Browse files
author
Sebastien Boeuf
committed
virtio-queue: Add helpers for accessing queue
These helpers are meant to help crate's consumers getting and setting information about the queue. Signed-off-by: Sebastien Boeuf <[email protected]>
1 parent c712790 commit fae1928

File tree

6 files changed

+160
-24
lines changed

6 files changed

+160
-24
lines changed

coverage_config_x86_64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 90.0,
2+
"coverage_score": 90.3,
33
"exclude_path": "crates/virtio-queue/src/mock.rs",
44
"crate_features": "virtio-blk/backend-stdio"
55
}

crates/virtio-queue/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ pub trait QueueStateT: for<'a> QueueStateGuard<'a> {
154154
/// Read the `idx` field from the available ring.
155155
fn avail_idx<M: GuestMemory>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error>;
156156

157+
/// Read the `idx` field from the used ring.
158+
fn used_idx<M: GuestMemory>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error>;
159+
157160
/// Put a used descriptor head into the used ring.
158161
fn add_used<M: GuestMemory>(&mut self, mem: &M, head_index: u16, len: u32)
159162
-> Result<(), Error>;
@@ -181,4 +184,10 @@ pub trait QueueStateT: for<'a> QueueStateGuard<'a> {
181184

182185
/// Set the index of the next entry in the available ring.
183186
fn set_next_avail(&mut self, next_avail: u16);
187+
188+
/// Return the index for the next descriptor in the used ring.
189+
fn next_used(&self) -> u16;
190+
191+
/// Set the index for the next descriptor in the used ring.
192+
fn set_next_used(&mut self, next_used: u16);
184193
}

crates/virtio-queue/src/queue.rs

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,14 @@ impl<M: GuestAddressSpace, S: QueueStateT> Queue<M, S> {
197197
self.state.avail_idx(self.mem.memory().deref(), order)
198198
}
199199

200+
/// Reads the `idx` field from the used ring.
201+
///
202+
/// # Arguments
203+
/// * `order` - the memory ordering used to access the `idx` field from memory.
204+
pub fn used_idx(&self, order: Ordering) -> Result<Wrapping<u16>, Error> {
205+
self.state.used_idx(self.mem.memory().deref(), order)
206+
}
207+
200208
/// Put a used descriptor head into the used ring.
201209
///
202210
/// # Arguments
@@ -236,13 +244,26 @@ impl<M: GuestAddressSpace, S: QueueStateT> Queue<M, S> {
236244
self.state.next_avail()
237245
}
238246

247+
/// Returns the index for the next descriptor in the used ring.
248+
pub fn next_used(&self) -> u16 {
249+
self.state.next_used()
250+
}
251+
239252
/// Set the index of the next entry in the available ring.
240253
///
241254
/// # Arguments
242255
/// * `next_avail` - the index of the next available ring entry.
243256
pub fn set_next_avail(&mut self, next_avail: u16) {
244257
self.state.set_next_avail(next_avail);
245258
}
259+
260+
/// Sets the index for the next descriptor in the used ring.
261+
///
262+
/// # Arguments
263+
/// * `next_used` - the index of the next used ring entry.
264+
pub fn set_next_used(&mut self, next_used: u16) {
265+
self.state.set_next_used(next_used);
266+
}
246267
}
247268

248269
impl<M: GuestAddressSpace> Queue<M, QueueState> {
@@ -257,7 +278,7 @@ mod tests {
257278
use super::*;
258279
use crate::defs::{
259280
DEFAULT_AVAIL_RING_ADDR, DEFAULT_DESC_TABLE_ADDR, DEFAULT_USED_RING_ADDR,
260-
VIRTQ_DESC_F_NEXT, VIRTQ_USED_F_NO_NOTIFY,
281+
VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE, VIRTQ_USED_F_NO_NOTIFY,
261282
};
262283
use crate::mock::MockSplitQueue;
263284
use crate::Descriptor;
@@ -348,6 +369,7 @@ mod tests {
348369
let vq = MockSplitQueue::new(m, 16);
349370
let mut q = vq.create_queue(m);
350371

372+
assert_eq!(q.used_idx(Ordering::Acquire).unwrap(), Wrapping(0));
351373
assert_eq!(u16::from_le(vq.used().idx().load()), 0);
352374

353375
// index too large
@@ -357,6 +379,7 @@ mod tests {
357379
// should be ok
358380
q.add_used(1, 0x1000).unwrap();
359381
assert_eq!(q.state.next_used, Wrapping(1));
382+
assert_eq!(q.used_idx(Ordering::Acquire).unwrap(), Wrapping(1));
360383
assert_eq!(u16::from_le(vq.used().idx().load()), 1);
361384

362385
let x = vq.used().ring().ref_at(0).load();
@@ -377,7 +400,7 @@ mod tests {
377400
// Same for `event_idx_enabled`, `next_avail` `next_used` and `signalled_used`.
378401
q.set_event_idx(true);
379402
q.set_next_avail(2);
380-
q.add_used(1, 200).unwrap();
403+
q.set_next_used(4);
381404
q.state.signalled_used = Some(Wrapping(15));
382405
assert_eq!(q.state.size, 8);
383406
// `create_queue` also marks the queue as ready.
@@ -533,10 +556,17 @@ mod tests {
533556
i += 1;
534557
q.disable_notification().unwrap();
535558

536-
while let Some(_chain) = q.iter().unwrap().next() {
537-
// Here the device would consume entries from the available ring, add an entry in
538-
// the used ring and optionally notify the driver. For the purpose of this test, we
539-
// don't need to do anything with the chain, only consume it.
559+
while let Some(chain) = q.iter().unwrap().next() {
560+
// Process the descriptor chain, and then add entries to the
561+
// used ring.
562+
let head_index = chain.head_index();
563+
let mut desc_len = 0;
564+
chain.for_each(|d| {
565+
if d.flags() & VIRTQ_DESC_F_WRITE == VIRTQ_DESC_F_WRITE {
566+
desc_len += d.len();
567+
}
568+
});
569+
q.add_used(head_index, desc_len).unwrap();
540570
}
541571
if !q.enable_notification().unwrap() {
542572
break;
@@ -547,6 +577,7 @@ mod tests {
547577
assert_eq!(i, 1);
548578
// The next chain that can be consumed should have index 2.
549579
assert_eq!(q.next_avail(), 2);
580+
assert_eq!(q.next_used(), 2);
550581
// Let the device know it can consume one more chain.
551582
vq.avail().idx().store(u16::to_le(3));
552583
i = 0;
@@ -555,8 +586,17 @@ mod tests {
555586
i += 1;
556587
q.disable_notification().unwrap();
557588

558-
while let Some(_chain) = q.iter().unwrap().next() {
559-
// In a real use case, we would do something with the chain here.
589+
while let Some(chain) = q.iter().unwrap().next() {
590+
// Process the descriptor chain, and then add entries to the
591+
// used ring.
592+
let head_index = chain.head_index();
593+
let mut desc_len = 0;
594+
chain.for_each(|d| {
595+
if d.flags() & VIRTQ_DESC_F_WRITE == VIRTQ_DESC_F_WRITE {
596+
desc_len += d.len();
597+
}
598+
});
599+
q.add_used(head_index, desc_len).unwrap();
560600
}
561601

562602
// For the simplicity of the test we are updating here the `idx` value of the available
@@ -571,21 +611,32 @@ mod tests {
571611
assert_eq!(i, 2);
572612
// The next chain that can be consumed should have index 4.
573613
assert_eq!(q.next_avail(), 4);
614+
assert_eq!(q.next_used(), 4);
574615

575616
// Set an `idx` that is bigger than the number of entries added in the ring.
576617
// This is an allowed scenario, but the indexes of the chain will have unexpected values.
577618
vq.avail().idx().store(u16::to_le(7));
578619
loop {
579620
q.disable_notification().unwrap();
580621

581-
while let Some(_chain) = q.iter().unwrap().next() {
582-
// In a real use case, we would do something with the chain here.
622+
while let Some(chain) = q.iter().unwrap().next() {
623+
// Process the descriptor chain, and then add entries to the
624+
// used ring.
625+
let head_index = chain.head_index();
626+
let mut desc_len = 0;
627+
chain.for_each(|d| {
628+
if d.flags() & VIRTQ_DESC_F_WRITE == VIRTQ_DESC_F_WRITE {
629+
desc_len += d.len();
630+
}
631+
});
632+
q.add_used(head_index, desc_len).unwrap();
583633
}
584634
if !q.enable_notification().unwrap() {
585635
break;
586636
}
587637
}
588638
assert_eq!(q.next_avail(), 7);
639+
assert_eq!(q.next_used(), 7);
589640
}
590641

591642
#[test]
@@ -619,14 +670,22 @@ mod tests {
619670
vq.avail().idx().store(u16::to_le(3));
620671
// No descriptor chains are consumed at this point.
621672
assert_eq!(q.next_avail(), 0);
673+
assert_eq!(q.next_used(), 0);
622674

623675
loop {
624676
q.disable_notification().unwrap();
625677

626-
while let Some(_chain) = q.iter().unwrap().next() {
627-
// Here the device would consume entries from the available ring, add an entry in
628-
// the used ring and optionally notify the driver. For the purpose of this test, we
629-
// don't need to do anything with the chain, only consume it.
678+
while let Some(chain) = q.iter().unwrap().next() {
679+
// Process the descriptor chain, and then add entries to the
680+
// used ring.
681+
let head_index = chain.head_index();
682+
let mut desc_len = 0;
683+
chain.for_each(|d| {
684+
if d.flags() & VIRTQ_DESC_F_WRITE == VIRTQ_DESC_F_WRITE {
685+
desc_len += d.len();
686+
}
687+
});
688+
q.add_used(head_index, desc_len).unwrap();
630689
}
631690
if !q.enable_notification().unwrap() {
632691
break;
@@ -635,6 +694,8 @@ mod tests {
635694
// The next chain that can be consumed should have index 3.
636695
assert_eq!(q.next_avail(), 3);
637696
assert_eq!(q.avail_idx(Ordering::Acquire).unwrap(), Wrapping(3));
697+
assert_eq!(q.next_used(), 3);
698+
assert_eq!(q.used_idx(Ordering::Acquire).unwrap(), Wrapping(3));
638699
assert!(q.lock().ready());
639700

640701
// Decrement `idx` which should be forbidden. We don't enforce this thing, but we should

crates/virtio-queue/src/queue_guard.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ where
138138
self.state.avail_idx(self.mem.deref(), order)
139139
}
140140

141+
/// Read the `idx` field from the used ring.
142+
pub fn used_idx(&self, order: Ordering) -> Result<Wrapping<u16>, Error> {
143+
self.state.used_idx(self.mem.deref(), order)
144+
}
145+
141146
/// Put a used descriptor head into the used ring.
142147
pub fn add_used(&mut self, head_index: u16, len: u32) -> Result<(), Error> {
143148
self.state.add_used(self.mem.deref(), head_index, len)
@@ -172,11 +177,21 @@ where
172177
self.state.next_avail()
173178
}
174179

180+
/// Return the index of the next entry in the used ring.
181+
pub fn next_used(&self) -> u16 {
182+
self.state.next_used()
183+
}
184+
175185
/// Set the index of the next entry in the available ring.
176186
pub fn set_next_avail(&mut self, next_avail: u16) {
177187
self.state.set_next_avail(next_avail);
178188
}
179189

190+
/// Set the index of the next entry in the used ring.
191+
pub fn set_next_used(&mut self, next_used: u16) {
192+
self.state.set_next_used(next_used);
193+
}
194+
180195
/// Get a consuming iterator over all available descriptor chain heads offered by the driver.
181196
pub fn iter(&mut self) -> Result<AvailIter<'_, M>, Error> {
182197
self.state.deref_mut().iter(self.mem.clone())
@@ -186,7 +201,7 @@ where
186201
#[cfg(test)]
187202
mod tests {
188203
use super::*;
189-
use crate::defs::VIRTQ_DESC_F_NEXT;
204+
use crate::defs::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
190205
use crate::mock::MockSplitQueue;
191206
use crate::Descriptor;
192207

@@ -223,14 +238,22 @@ mod tests {
223238
vq.avail().idx().store(3);
224239
// No descriptor chains are consumed at this point.
225240
assert_eq!(g.next_avail(), 0);
241+
assert_eq!(g.next_used(), 0);
226242

227243
loop {
228244
g.disable_notification().unwrap();
229245

230-
while let Some(_chain) = g.iter().unwrap().next() {
231-
// Here the device would consume entries from the available ring, add an entry in
232-
// the used ring and optionally notify the driver. For the purpose of this test, we
233-
// don't need to do anything with the chain, only consume it.
246+
while let Some(chain) = g.iter().unwrap().next() {
247+
// Process the descriptor chain, and then add entries to the
248+
// used ring.
249+
let head_index = chain.head_index();
250+
let mut desc_len = 0;
251+
chain.for_each(|d| {
252+
if d.flags() & VIRTQ_DESC_F_WRITE == VIRTQ_DESC_F_WRITE {
253+
desc_len += d.len();
254+
}
255+
});
256+
g.add_used(head_index, desc_len).unwrap();
234257
}
235258
if !g.enable_notification().unwrap() {
236259
break;
@@ -239,6 +262,8 @@ mod tests {
239262
// The next chain that can be consumed should have index 3.
240263
assert_eq!(g.next_avail(), 3);
241264
assert_eq!(g.avail_idx(Ordering::Acquire).unwrap(), Wrapping(3));
265+
assert_eq!(g.next_used(), 3);
266+
assert_eq!(g.used_idx(Ordering::Acquire).unwrap(), Wrapping(3));
242267
assert!(g.ready());
243268

244269
// Decrement `idx` which should be forbidden. We don't enforce this thing, but we should

crates/virtio-queue/src/state.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,17 @@ impl QueueStateT for QueueState {
311311
.map_err(Error::GuestMemory)
312312
}
313313

314+
fn used_idx<M: GuestMemory>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error> {
315+
let addr = self
316+
.used_ring
317+
.checked_add(2)
318+
.ok_or(Error::AddressOverflow)?;
319+
320+
mem.load(addr, order)
321+
.map(Wrapping)
322+
.map_err(Error::GuestMemory)
323+
}
324+
314325
fn add_used<M: GuestMemory>(
315326
&mut self,
316327
mem: &M,
@@ -415,7 +426,15 @@ impl QueueStateT for QueueState {
415426
self.next_avail.0
416427
}
417428

429+
fn next_used(&self) -> u16 {
430+
self.next_used.0
431+
}
432+
418433
fn set_next_avail(&mut self, next_avail: u16) {
419434
self.next_avail = Wrapping(next_avail);
420435
}
436+
437+
fn set_next_used(&mut self, next_used: u16) {
438+
self.next_used = Wrapping(next_used);
439+
}
421440
}

0 commit comments

Comments
 (0)