@@ -390,14 +390,21 @@ impl Queue {
390390 fn do_pop_unchecked < ' b , M : GuestMemory > (
391391 & mut self ,
392392 mem : & ' b M ,
393+ ) -> Option < DescriptorChain < ' b , M > > {
394+ self . get_desc_chain ( self . next_avail . 0 , mem) . inspect ( |_| {
395+ self . next_avail += Wrapping ( 1 ) ;
396+ } )
397+ }
398+
399+ /// Get descriptor chain from the avail ring at the specified index.
400+ pub fn get_desc_chain < ' b , M : GuestMemory > (
401+ & self ,
402+ avail_idx : u16 ,
403+ mem : & ' b M ,
393404 ) -> Option < DescriptorChain < ' b , M > > {
394405 // This fence ensures all subsequent reads see the updated driver writes.
395406 fence ( Ordering :: Acquire ) ;
396407
397- // We'll need to find the first available descriptor, that we haven't yet popped.
398- // In a naive notation, that would be:
399- // `descriptor_table[avail_ring[next_avail]]`.
400- //
401408 // Avail ring has layout:
402409 // struct AvailRing {
403410 // flags: u16,
@@ -408,20 +415,17 @@ impl Queue {
408415 // We calculate offset into `ring` field.
409416 let desc_index_offset = std:: mem:: size_of :: < u16 > ( )
410417 + std:: mem:: size_of :: < u16 > ( )
411- + std:: mem:: size_of :: < u16 > ( ) * usize:: from ( self . next_avail . 0 % self . actual_size ( ) ) ;
412- let desc_index_address = self . avail_ring . unchecked_add ( usize_to_u64 ( desc_index_offset) ) ;
418+ + std:: mem:: size_of :: < u16 > ( ) * usize:: from ( avail_idx % self . actual_size ( ) ) ;
419+ let desc_index_address = self
420+ . avail_ring
421+ . unchecked_add ( usize_to_u64 ( desc_index_offset) ) ;
413422
414- // `self.is_valid()` already performed all the bound checks on the descriptor table
415- // and virtq rings, so it's safe to unwrap guest memory reads and to use unchecked
416- // offsets .
423+ // SAFETY:
424+ // `desc_index_address` param is bounded by size of the queue as `avail_idx` is
425+ // modded by `actual_size()` .
417426 let desc_index: u16 = mem. read_obj ( desc_index_address) . unwrap ( ) ;
418427
419- DescriptorChain :: checked_new ( mem, self . desc_table , self . actual_size ( ) , desc_index) . map (
420- |dc| {
421- self . next_avail += Wrapping ( 1 ) ;
422- dc
423- } ,
424- )
428+ DescriptorChain :: checked_new ( mem, self . desc_table , self . actual_size ( ) , desc_index)
425429 }
426430
427431 /// Undo the effects of the last `self.pop()` call.
0 commit comments