@@ -40,6 +40,7 @@ use versionize::{VersionMap, Versionize, VersionizeResult};
4040use versionize_derive:: Versionize ;
4141use virtio_bindings:: virtio_blk:: * ;
4242use virtio_bindings:: virtio_config:: * ;
43+ use virtio_bindings:: virtio_ring:: VIRTIO_RING_F_EVENT_IDX ;
4344use virtio_queue:: { Queue , QueueOwnedT , QueueT } ;
4445use vm_memory:: { ByteValued , Bytes , GuestAddressSpace , GuestMemoryAtomic , GuestMemoryError } ;
4546use vm_migration:: VersionMapped ;
@@ -80,6 +81,8 @@ pub enum Error {
8081 QueueIterator ( virtio_queue:: Error ) ,
8182 #[ error( "Failed to update request status: {0}" ) ]
8283 RequestStatus ( GuestMemoryError ) ,
84+ #[ error( "Failed to enable notification: {0}" ) ]
85+ QueueEnableNotification ( virtio_queue:: Error ) ,
8386}
8487
8588pub type Result < T > = result:: Result < T , Error > ;
@@ -137,11 +140,9 @@ struct BlockEpollHandler {
137140}
138141
139142impl BlockEpollHandler {
140- fn process_queue_submit ( & mut self ) -> Result < bool > {
143+ fn process_queue_submit ( & mut self ) -> Result < ( ) > {
141144 let queue = & mut self . queue ;
142145
143- let mut used_descs = false ;
144-
145146 while let Some ( mut desc_chain) = queue. pop_descriptor_chain ( self . mem . memory ( ) ) {
146147 let mut request = Request :: parse ( & mut desc_chain, self . access_platform . as_ref ( ) )
147148 . map_err ( Error :: RequestParsing ) ?;
@@ -163,7 +164,9 @@ impl BlockEpollHandler {
163164 queue
164165 . add_used ( desc_chain. memory ( ) , desc_chain. head_index ( ) , 0 )
165166 . map_err ( Error :: QueueAddUsed ) ?;
166- used_descs = true ;
167+ queue
168+ . enable_notification ( self . mem . memory ( ) . deref ( ) )
169+ . map_err ( Error :: QueueEnableNotification ) ?;
167170 continue ;
168171 }
169172
@@ -223,23 +226,34 @@ impl BlockEpollHandler {
223226 queue
224227 . add_used ( desc_chain. memory ( ) , desc_chain. head_index ( ) , 0 )
225228 . map_err ( Error :: QueueAddUsed ) ?;
226- used_descs = true ;
229+ queue
230+ . enable_notification ( self . mem . memory ( ) . deref ( ) )
231+ . map_err ( Error :: QueueEnableNotification ) ?;
227232 }
228233 }
229234
230- Ok ( used_descs )
235+ Ok ( ( ) )
231236 }
232237
233238 fn process_queue_submit_and_signal ( & mut self ) -> result:: Result < ( ) , EpollHelperError > {
234- let needs_notification = self . process_queue_submit ( ) . map_err ( |e| {
239+ self . process_queue_submit ( ) . map_err ( |e| {
235240 EpollHelperError :: HandleEvent ( anyhow ! ( "Failed to process queue (submit): {:?}" , e) )
236241 } ) ?;
237242
238- if needs_notification {
243+ if self
244+ . queue
245+ . needs_notification ( self . mem . memory ( ) . deref ( ) )
246+ . map_err ( |e| {
247+ EpollHelperError :: HandleEvent ( anyhow ! (
248+ "Failed to check needs_notification: {:?}" ,
249+ e
250+ ) )
251+ } ) ?
252+ {
239253 self . signal_used_queue ( ) . map_err ( |e| {
240254 EpollHelperError :: HandleEvent ( anyhow ! ( "Failed to signal used queue: {:?}" , e) )
241- } ) ?
242- } ;
255+ } ) ?;
256+ }
243257
244258 Ok ( ( ) )
245259 }
@@ -265,8 +279,7 @@ impl BlockEpollHandler {
265279 Err ( Error :: MissingEntryRequestList )
266280 }
267281
268- fn process_queue_complete ( & mut self ) -> Result < bool > {
269- let mut used_descs = false ;
282+ fn process_queue_complete ( & mut self ) -> Result < ( ) > {
270283 let mem = self . mem . memory ( ) ;
271284 let mut read_bytes = Wrapping ( 0 ) ;
272285 let mut write_bytes = Wrapping ( 0 ) ;
@@ -379,7 +392,9 @@ impl BlockEpollHandler {
379392 queue
380393 . add_used ( mem. deref ( ) , desc_index, len)
381394 . map_err ( Error :: QueueAddUsed ) ?;
382- used_descs = true ;
395+ queue
396+ . enable_notification ( mem. deref ( ) )
397+ . map_err ( Error :: QueueEnableNotification ) ?;
383398 }
384399
385400 self . counters
@@ -396,7 +411,7 @@ impl BlockEpollHandler {
396411 . read_ops
397412 . fetch_add ( read_ops. 0 , Ordering :: AcqRel ) ;
398413
399- Ok ( used_descs )
414+ Ok ( ( ) )
400415 }
401416
402417 fn signal_used_queue ( & self ) -> result:: Result < ( ) , DeviceError > {
@@ -451,20 +466,19 @@ impl EpollHelperHandler for BlockEpollHandler {
451466 EpollHelperError :: HandleEvent ( anyhow ! ( "Failed to get queue event: {:?}" , e) )
452467 } ) ?;
453468
454- let needs_notification = self . process_queue_complete ( ) . map_err ( |e| {
469+ self . process_queue_complete ( ) . map_err ( |e| {
455470 EpollHelperError :: HandleEvent ( anyhow ! (
456471 "Failed to process queue (complete): {:?}" ,
457472 e
458473 ) )
459474 } ) ?;
460475
461- if needs_notification {
462- self . signal_used_queue ( ) . map_err ( |e| {
463- EpollHelperError :: HandleEvent ( anyhow ! (
464- "Failed to signal used queue: {:?}" ,
465- e
466- ) )
467- } ) ?;
476+ let rate_limit_reached =
477+ self . rate_limiter . as_ref ( ) . map_or ( false , |r| r. is_blocked ( ) ) ;
478+
479+ // Process the queue only when the rate limit is not reached
480+ if !rate_limit_reached {
481+ self . process_queue_submit_and_signal ( ) ?
468482 }
469483 }
470484 RATE_LIMITER_EVENT => {
@@ -570,7 +584,8 @@ impl Block {
570584 | ( 1u64 << VIRTIO_BLK_F_FLUSH )
571585 | ( 1u64 << VIRTIO_BLK_F_CONFIG_WCE )
572586 | ( 1u64 << VIRTIO_BLK_F_BLK_SIZE )
573- | ( 1u64 << VIRTIO_BLK_F_TOPOLOGY ) ;
587+ | ( 1u64 << VIRTIO_BLK_F_TOPOLOGY )
588+ | ( 1u64 << VIRTIO_RING_F_EVENT_IDX ) ;
574589
575590 if iommu {
576591 avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM ;
@@ -742,8 +757,12 @@ impl VirtioDevice for Block {
742757 self . update_writeback ( ) ;
743758
744759 let mut epoll_threads = Vec :: new ( ) ;
760+ let event_idx = self . common . feature_acked ( VIRTIO_RING_F_EVENT_IDX . into ( ) ) ;
761+
745762 for i in 0 ..queues. len ( ) {
746- let ( _, queue, queue_evt) = queues. remove ( 0 ) ;
763+ let ( _, mut queue, queue_evt) = queues. remove ( 0 ) ;
764+ queue. set_event_idx ( event_idx) ;
765+
747766 let queue_size = queue. size ( ) ;
748767 let ( kill_evt, pause_evt) = self . common . dup_eventfds ( ) ;
749768
0 commit comments