@@ -369,6 +369,12 @@ impl RingCursor {
369369 pub fn wrap ( & self ) -> bool {
370370 self . wrap
371371 }
372+
373+ /// Reset cursor to initial state.
374+ pub fn reset ( & mut self ) {
375+ self . head = 0 ;
376+ self . wrap = true ;
377+ }
372378}
373379
374380/// Producer (driver) side of a packed virtqueue.
@@ -817,6 +823,18 @@ impl<M: MemOps> RingProducer<M> {
817823
818824 Ok ( should_notify ( evt, self . len ( ) as u16 , old, new) )
819825 }
826+
827+ /// Reset to initial state matching a freshly zeroed ring.
828+ pub fn reset ( & mut self ) {
829+ let size = self . desc_table . len ( ) ;
830+ self . avail_cursor . reset ( ) ;
831+ self . used_cursor . reset ( ) ;
832+ self . num_free = size;
833+ self . id_free . clear ( ) ;
834+ self . id_free . extend ( 0 ..size as u16 ) ;
835+ self . id_num . iter_mut ( ) . for_each ( |n| * n = 0 ) ;
836+ self . event_flags_shadow = EventFlags :: ENABLE ;
837+ }
820838}
821839
822840/// Consumer (device) side of a packed virtqueue.
@@ -1164,6 +1182,16 @@ impl<M: MemOps> RingConsumer<M> {
11641182
11651183 Ok ( should_notify ( evt, self . desc_table . len ( ) as u16 , old, new) )
11661184 }
1185+
1186+ /// Reset to initial state matching a freshly zeroed ring.
1187+ /// Does not reallocate internal buffers.
1188+ pub fn reset ( & mut self ) {
1189+ self . avail_cursor . reset ( ) ;
1190+ self . used_cursor . reset ( ) ;
1191+ self . id_num . iter_mut ( ) . for_each ( |n| * n = 0 ) ;
1192+ self . num_inflight = 0 ;
1193+ self . event_flags_shadow = EventFlags :: ENABLE ;
1194+ }
11671195}
11681196
11691197/// Common packed-ring notification decision:
@@ -2974,6 +3002,113 @@ pub(crate) mod tests {
29743002 let ( _, _) = consumer. poll_available ( ) . unwrap ( ) ;
29753003 }
29763004 }
3005+
3006+ #[ test]
3007+ fn test_ring_cursor_reset ( ) {
3008+ let mut cursor = RingCursor :: new ( 16 ) ;
3009+ cursor. advance_by ( 5 ) ;
3010+ assert_eq ! ( cursor. head( ) , 5 ) ;
3011+
3012+ cursor. reset ( ) ;
3013+ assert_eq ! ( cursor, RingCursor :: new( 16 ) ) ;
3014+ assert_eq ! ( cursor. head( ) , 0 ) ;
3015+ assert ! ( cursor. wrap( ) ) ;
3016+ }
3017+
3018+ #[ test]
3019+ fn test_ring_cursor_reset_after_wrap ( ) {
3020+ let mut cursor = RingCursor :: new ( 4 ) ;
3021+ // Advance past the wrap point
3022+ cursor. advance_by ( 5 ) ;
3023+ assert_eq ! ( cursor. head( ) , 1 ) ;
3024+ assert ! ( !cursor. wrap( ) ) ;
3025+
3026+ cursor. reset ( ) ;
3027+ assert_eq ! ( cursor. head( ) , 0 ) ;
3028+ assert ! ( cursor. wrap( ) ) ;
3029+ }
3030+
3031+ #[ test]
3032+ fn test_ring_producer_reset_matches_new ( ) {
3033+ let ring = make_ring ( 8 ) ;
3034+ let fresh = make_producer ( & ring) ;
3035+
3036+ let mut used = make_producer ( & ring) ;
3037+ // Mutate state
3038+ used. submit_one ( 0x1000 , 64 , false ) . unwrap ( ) ;
3039+ used. submit_one ( 0x2000 , 128 , true ) . unwrap ( ) ;
3040+
3041+ used. reset ( ) ;
3042+
3043+ assert_eq ! ( used. avail_cursor, fresh. avail_cursor) ;
3044+ assert_eq ! ( used. used_cursor, fresh. used_cursor) ;
3045+ assert_eq ! ( used. num_free, fresh. num_free) ;
3046+ assert_eq ! ( used. id_free. len( ) , fresh. id_free. len( ) ) ;
3047+ assert_eq ! ( used. id_num. as_slice( ) , fresh. id_num. as_slice( ) ) ;
3048+ assert_eq ! ( used. event_flags_shadow, fresh. event_flags_shadow) ;
3049+ }
3050+
3051+ #[ test]
3052+ fn test_ring_producer_reset_id_free_complete ( ) {
3053+ let ring = make_ring ( 8 ) ;
3054+ let mut producer = make_producer ( & ring) ;
3055+
3056+ // Submit and consume several descriptors
3057+ for i in 0 ..4u64 {
3058+ producer. submit_one ( 0x1000 + i * 0x100 , 64 , false ) . unwrap ( ) ;
3059+ }
3060+ assert_eq ! ( producer. num_free, 4 ) ;
3061+
3062+ producer. reset ( ) ;
3063+
3064+ assert_eq ! ( producer. num_free, 8 ) ;
3065+ assert_eq ! ( producer. id_free. len( ) , 8 ) ;
3066+ // All IDs 0..8 should be present
3067+ for id in 0 ..8u16 {
3068+ assert ! ( producer. id_free. contains( & id) ) ;
3069+ }
3070+ }
3071+
3072+ #[ test]
3073+ fn test_ring_consumer_reset_matches_new ( ) {
3074+ let ring = make_ring ( 8 ) ;
3075+ let fresh = make_consumer ( & ring) ;
3076+
3077+ let mut used = make_consumer ( & ring) ;
3078+
3079+ // Submit from producer side so consumer has something to poll
3080+ let mut producer = make_producer ( & ring) ;
3081+ producer. submit_one ( 0x1000 , 64 , false ) . unwrap ( ) ;
3082+
3083+ // Consumer polls the available descriptor
3084+ let ( id, _chain) = used. poll_available ( ) . unwrap ( ) ;
3085+ used. submit_used ( id, 64 ) . unwrap ( ) ;
3086+
3087+ used. reset ( ) ;
3088+
3089+ assert_eq ! ( used. avail_cursor, fresh. avail_cursor) ;
3090+ assert_eq ! ( used. used_cursor, fresh. used_cursor) ;
3091+ assert_eq ! ( used. id_num. as_slice( ) , fresh. id_num. as_slice( ) ) ;
3092+ assert_eq ! ( used. num_inflight, fresh. num_inflight) ;
3093+ assert_eq ! ( used. event_flags_shadow, fresh. event_flags_shadow) ;
3094+ }
3095+
3096+ #[ test]
3097+ fn test_ring_consumer_reset_clears_inflight ( ) {
3098+ let ring = make_ring ( 8 ) ;
3099+ let mut producer = make_producer ( & ring) ;
3100+ let mut consumer = make_consumer ( & ring) ;
3101+
3102+ // Submit and poll two items (consume but do not complete)
3103+ producer. submit_one ( 0x1000 , 64 , false ) . unwrap ( ) ;
3104+ producer. submit_one ( 0x2000 , 64 , false ) . unwrap ( ) ;
3105+ let _ = consumer. poll_available ( ) . unwrap ( ) ;
3106+ let _ = consumer. poll_available ( ) . unwrap ( ) ;
3107+ assert_eq ! ( consumer. num_inflight, 2 ) ;
3108+
3109+ consumer. reset ( ) ;
3110+ assert_eq ! ( consumer. num_inflight, 0 ) ;
3111+ }
29773112}
29783113
29793114#[ cfg( test) ]
0 commit comments