Skip to content

Commit 49783e8

Browse files
committed
feat(queue): add read_used_ring and discard_used
Add `read_used_ring` to read used element from a used ring. This is needed for `discard_used`. Add `discard_used` method to discard last `n` used elements in the used ring by setting their `len` to 0. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 2eac169 commit 49783e8

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

src/vmm/src/devices/virtio/queue.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,23 @@ impl Queue {
468468
self.set_used_ring_idx(self.next_used.0, mem);
469469
}
470470

471+
/// Discards last `n` descriptors by setting their len to 0.
472+
pub fn discard_used<M: GuestMemory>(&mut self, mem: &M, n: u16) {
473+
// `next_used` is pointing to the next descriptor index.
474+
// So we use range 1..n + 1 to get indexes of last n descriptors.
475+
for i in 1..n + 1 {
476+
let next_used_index = self.next_used - Wrapping(i);
477+
let mut used_element = self.read_used_ring(mem, next_used_index.0);
478+
used_element.len = 0;
479+
// SAFETY:
480+
// This should never panic as we only update len of the used_element.
481+
self.write_used_ring(mem, next_used_index.0, used_element)
482+
.unwrap();
483+
}
484+
}
485+
486+
/// Read used element to the used ring at specified index.
487+
#[inline(always)]
471488
fn write_used_ring<M: GuestMemory>(
472489
&self,
473490
mem: &M,
@@ -505,6 +522,31 @@ impl Queue {
505522
Ok(())
506523
}
507524

525+
/// Read used element from a used ring at specified index.
526+
#[inline(always)]
527+
fn read_used_ring<M: GuestMemory>(&self, mem: &M, index: u16) -> UsedElement {
528+
// Used ring has layout:
529+
// struct UsedRing {
530+
// flags: u16,
531+
// idx: u16,
532+
// ring: [UsedElement; <queue size>],
533+
// avail_event: u16,
534+
// }
535+
// We calculate offset into `ring` field.
536+
let used_ring_offset = std::mem::size_of::<u16>()
537+
+ std::mem::size_of::<u16>()
538+
+ std::mem::size_of::<UsedElement>() * usize::from(index % self.actual_size());
539+
let used_element_address = self.used_ring.unchecked_add(usize_to_u64(used_ring_offset));
540+
541+
// SAFETY:
542+
// `used_element_address` param is bounded by size of the queue as `index` is
543+
// modded by `actual_size()`.
544+
// `self.is_valid()` already performed all the bound checks on the descriptor table
545+
// and virtq rings, so it's safe to unwrap guest memory reads and to use unchecked
546+
// offsets.
547+
mem.read_obj(used_element_address).unwrap()
548+
}
549+
508550
/// Fetch the available ring index (`virtq_avail->idx`) from guest memory.
509551
/// This is written by the driver, to indicate the next slot that will be filled in the avail
510552
/// ring.

0 commit comments

Comments
 (0)