@@ -19,7 +19,6 @@ use guestmem::GuestMemoryError;
1919use inspect:: Inspect ;
2020use pal_async:: wait:: PolledWait ;
2121use pal_event:: Event ;
22- use parking_lot:: Mutex ;
2322use std:: io:: Error ;
2423use std:: pin:: Pin ;
2524use std:: sync:: Arc ;
@@ -98,67 +97,21 @@ fn read_from_payload_at_offset(
9897 Ok ( read_bytes)
9998}
10099
101- #[ derive( Debug ) ]
102- pub ( crate ) struct VirtioQueueUsedHandler {
103- core : QueueCoreCompleteWork ,
104- notify_guest : Interrupt ,
105- }
106-
107- impl VirtioQueueUsedHandler {
108- pub ( crate ) fn new ( core : QueueCoreCompleteWork , notify_guest : Interrupt ) -> Self {
109- Self { core, notify_guest }
110- }
111-
112- pub ( crate ) fn complete_descriptor ( & mut self , work : & QueueWork , bytes_written : u32 ) {
113- match self . core . complete_descriptor ( work, bytes_written) {
114- Ok ( true ) => {
115- self . notify_guest . deliver ( ) ;
116- }
117- Ok ( false ) => { }
118- Err ( err) => {
119- tracelimit:: error_ratelimited!(
120- error = & err as & dyn std:: error:: Error ,
121- "failed to complete descriptor"
122- ) ;
123- }
124- }
125- }
126- }
127-
128100/// A descriptor chain popped from a [`VirtioQueue`].
129101///
130- /// The device must call [`complete`](Self ::complete) exactly once to post a
102+ /// The device must call [`VirtioQueue ::complete`] exactly once to post a
131103/// completion to the guest's used ring. Dropping without completing is a bug
132104/// and will not automatically post a completion.
133105#[ must_use]
134106pub struct VirtioQueueCallbackWork {
135- used_queue_handler : Arc < Mutex < VirtioQueueUsedHandler > > ,
136107 work : QueueWork ,
137108 pub payload : Vec < VirtioQueuePayload > ,
138- completed : bool ,
139109}
140110
141111impl VirtioQueueCallbackWork {
142- pub ( crate ) fn new (
143- mut work : QueueWork ,
144- used_queue_handler : & Arc < Mutex < VirtioQueueUsedHandler > > ,
145- ) -> Self {
146- let used_queue_handler = used_queue_handler. clone ( ) ;
112+ pub ( crate ) fn new ( mut work : QueueWork ) -> Self {
147113 let payload = std:: mem:: take ( & mut work. payload ) ;
148- Self {
149- work,
150- payload,
151- used_queue_handler,
152- completed : false ,
153- }
154- }
155-
156- pub fn complete ( & mut self , bytes_written : u32 ) {
157- assert ! ( !self . completed) ;
158- self . used_queue_handler
159- . lock ( )
160- . complete_descriptor ( & self . work , bytes_written) ;
161- self . completed = true ;
114+ Self { work, payload }
162115 }
163116
164117 pub fn descriptor_index ( & self ) -> u16 {
@@ -290,10 +243,10 @@ impl<'a> PeekedWork<'a> {
290243 /// Consume this peeked work, advancing the queue's available index.
291244 ///
292245 /// Returns a [`VirtioQueueCallbackWork`] that must be explicitly
293- /// completed via [`VirtioQueueCallbackWork ::complete`].
246+ /// completed via [`VirtioQueue ::complete`].
294247 pub fn consume ( self ) -> VirtioQueueCallbackWork {
295248 self . queue . core . advance ( & self . work ) ;
296- VirtioQueueCallbackWork :: new ( self . work , & self . queue . used_handler )
249+ VirtioQueueCallbackWork :: new ( self . work )
297250 }
298251}
299252
@@ -302,7 +255,9 @@ pub struct VirtioQueue {
302255 #[ inspect( flatten) ]
303256 core : QueueCoreGetWork ,
304257 #[ inspect( skip) ]
305- used_handler : Arc < Mutex < VirtioQueueUsedHandler > > ,
258+ complete : QueueCoreCompleteWork ,
259+ #[ inspect( skip) ]
260+ notify_guest : Interrupt ,
306261 #[ inspect( skip) ]
307262 queue_event : PolledWait < Event > ,
308263}
@@ -317,13 +272,10 @@ impl VirtioQueue {
317272 initial_state : Option < QueueState > ,
318273 ) -> Result < Self , QueueError > {
319274 let ( get_work, complete_work) = new_queue ( features, mem, params, initial_state) ?;
320- let used_handler = Arc :: new ( Mutex :: new ( VirtioQueueUsedHandler :: new (
321- complete_work,
322- notify,
323- ) ) ) ;
324275 Ok ( Self {
325276 core : get_work,
326- used_handler,
277+ complete : complete_work,
278+ notify_guest : notify,
327279 queue_event,
328280 } )
329281 }
@@ -332,7 +284,7 @@ impl VirtioQueue {
332284 pub fn queue_state ( & self ) -> QueueState {
333285 QueueState {
334286 avail_index : self . core . avail_index ( ) ,
335- used_index : self . used_handler . lock ( ) . core . used_index ( ) ,
287+ used_index : self . complete . used_index ( ) ,
336288 }
337289 }
338290
@@ -362,7 +314,7 @@ impl VirtioQueue {
362314 . core
363315 . try_next_work ( )
364316 . map_err ( Error :: other) ?
365- . map ( |work| VirtioQueueCallbackWork :: new ( work , & self . used_handler ) ) )
317+ . map ( VirtioQueueCallbackWork :: new) )
366318 }
367319
368320 /// Peek at the next available descriptor without advancing the available
@@ -402,6 +354,28 @@ impl VirtioQueue {
402354 Ok ( PeekedWork :: new ( self , work) )
403355 }
404356
357+ /// Complete a descriptor previously obtained from this queue.
358+ ///
359+ /// Writes `bytes_written` to the used ring and delivers an interrupt
360+ /// to the guest (unless interrupt suppression is active).
361+ ///
362+ /// Takes ownership of the work item, ensuring it can only be completed
363+ /// once.
364+ pub fn complete ( & mut self , work : VirtioQueueCallbackWork , bytes_written : u32 ) {
365+ match self . complete . complete_descriptor ( & work. work , bytes_written) {
366+ Ok ( true ) => {
367+ self . notify_guest . deliver ( ) ;
368+ }
369+ Ok ( false ) => { }
370+ Err ( err) => {
371+ tracelimit:: error_ratelimited!(
372+ error = & err as & dyn std:: error:: Error ,
373+ "failed to complete descriptor"
374+ ) ;
375+ }
376+ }
377+ }
378+
405379 fn poll_next_buffer (
406380 & mut self ,
407381 cx : & mut Context < ' _ > ,
@@ -415,14 +389,6 @@ impl VirtioQueue {
415389 }
416390}
417391
418- impl Drop for VirtioQueue {
419- fn drop ( & mut self ) {
420- if Arc :: get_mut ( & mut self . used_handler ) . is_none ( ) {
421- tracing:: error!( "Virtio queue dropped with outstanding work pending" )
422- }
423- }
424- }
425-
426392impl Stream for VirtioQueue {
427393 type Item = Result < VirtioQueueCallbackWork , Error > ;
428394
0 commit comments