@@ -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
248269impl < 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.
@@ -510,7 +533,7 @@ mod tests {
510533 for i in 0 ..13 {
511534 let flags = match i {
512535 1 | 4 | 6 | 8 | 12 => 0 ,
513- _ => VIRTQ_DESC_F_NEXT ,
536+ _ => VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE ,
514537 } ;
515538
516539 let desc = Descriptor :: new ( ( 0x1000 * ( i + 1 ) ) as u64 , 0x1000 , flags, i + 1 ) ;
@@ -533,10 +556,13 @@ 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| desc_len += d. len ( ) ) ;
565+ q. add_used ( head_index, desc_len) . unwrap ( ) ;
540566 }
541567 if !q. enable_notification ( ) . unwrap ( ) {
542568 break ;
@@ -547,6 +573,7 @@ mod tests {
547573 assert_eq ! ( i, 1 ) ;
548574 // The next chain that can be consumed should have index 2.
549575 assert_eq ! ( q. next_avail( ) , 2 ) ;
576+ assert_eq ! ( q. next_used( ) , 2 ) ;
550577 // Let the device know it can consume one more chain.
551578 vq. avail ( ) . idx ( ) . store ( u16:: to_le ( 3 ) ) ;
552579 i = 0 ;
@@ -555,8 +582,19 @@ mod tests {
555582 i += 1 ;
556583 q. disable_notification ( ) . unwrap ( ) ;
557584
558- while let Some ( _chain) = q. iter ( ) . unwrap ( ) . next ( ) {
559- // In a real use case, we would do something with the chain here.
585+ while let Some ( chain) = q. iter ( ) . unwrap ( ) . next ( ) {
586+ // Process the descriptor chain, and then add entries to the
587+ // used ring.
588+ let head_index = chain. head_index ( ) ;
589+ let mut desc_len = 0 ;
590+ chain. for_each ( |d| {
591+ if d. flags ( ) & VIRTQ_DESC_F_WRITE == VIRTQ_DESC_F_WRITE {
592+ desc_len += d. len ( ) ;
593+ }
594+ } ) ;
595+ if desc_len > 0 {
596+ q. add_used ( head_index, desc_len) . unwrap ( ) ;
597+ }
560598 }
561599
562600 // For the simplicity of the test we are updating here the `idx` value of the available
@@ -571,21 +609,28 @@ mod tests {
571609 assert_eq ! ( i, 2 ) ;
572610 // The next chain that can be consumed should have index 4.
573611 assert_eq ! ( q. next_avail( ) , 4 ) ;
612+ assert_eq ! ( q. next_used( ) , 4 ) ;
574613
575614 // Set an `idx` that is bigger than the number of entries added in the ring.
576615 // This is an allowed scenario, but the indexes of the chain will have unexpected values.
577616 vq. avail ( ) . idx ( ) . store ( u16:: to_le ( 7 ) ) ;
578617 loop {
579618 q. disable_notification ( ) . unwrap ( ) ;
580619
581- while let Some ( _chain) = q. iter ( ) . unwrap ( ) . next ( ) {
582- // In a real use case, we would do something with the chain here.
620+ while let Some ( chain) = q. iter ( ) . unwrap ( ) . next ( ) {
621+ // Process the descriptor chain, and then add entries to the
622+ // used ring.
623+ let head_index = chain. head_index ( ) ;
624+ let mut desc_len = 0 ;
625+ chain. for_each ( |d| desc_len += d. len ( ) ) ;
626+ q. add_used ( head_index, desc_len) . unwrap ( ) ;
583627 }
584628 if !q. enable_notification ( ) . unwrap ( ) {
585629 break ;
586630 }
587631 }
588632 assert_eq ! ( q. next_avail( ) , 7 ) ;
633+ assert_eq ! ( q. next_used( ) , 7 ) ;
589634 }
590635
591636 #[ test]
@@ -619,14 +664,18 @@ mod tests {
619664 vq. avail ( ) . idx ( ) . store ( u16:: to_le ( 3 ) ) ;
620665 // No descriptor chains are consumed at this point.
621666 assert_eq ! ( q. next_avail( ) , 0 ) ;
667+ assert_eq ! ( q. next_used( ) , 0 ) ;
622668
623669 loop {
624670 q. disable_notification ( ) . unwrap ( ) ;
625671
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.
672+ while let Some ( chain) = q. iter ( ) . unwrap ( ) . next ( ) {
673+ // Process the descriptor chain, and then add entries to the
674+ // used ring.
675+ let head_index = chain. head_index ( ) ;
676+ let mut desc_len = 0 ;
677+ chain. for_each ( |d| desc_len += d. len ( ) ) ;
678+ q. add_used ( head_index, desc_len) . unwrap ( ) ;
630679 }
631680 if !q. enable_notification ( ) . unwrap ( ) {
632681 break ;
@@ -635,6 +684,8 @@ mod tests {
635684 // The next chain that can be consumed should have index 3.
636685 assert_eq ! ( q. next_avail( ) , 3 ) ;
637686 assert_eq ! ( q. avail_idx( Ordering :: Acquire ) . unwrap( ) , Wrapping ( 3 ) ) ;
687+ assert_eq ! ( q. next_used( ) , 3 ) ;
688+ assert_eq ! ( q. used_idx( Ordering :: Acquire ) . unwrap( ) , Wrapping ( 3 ) ) ;
638689 assert ! ( q. lock( ) . ready( ) ) ;
639690
640691 // Decrement `idx` which should be forbidden. We don't enforce this thing, but we should
0 commit comments