@@ -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