@@ -254,8 +254,9 @@ impl Pmem {
254254 // This is safe since we checked in the event handler that the device is activated.
255255 let active_state = self . device_state . active_state ( ) . unwrap ( ) ;
256256
257+ let mut cached_result = None ;
257258 while let Some ( head) = self . queues [ 0 ] . pop ( ) ? {
258- let add_result = match self . process_chain ( head) {
259+ let add_result = match self . process_chain ( head, & mut cached_result ) {
259260 Ok ( ( ) ) => self . queues [ 0 ] . add_used ( head. index , 4 ) ,
260261 Err ( err) => {
261262 error ! ( "pmem: {err}" ) ;
@@ -283,7 +284,11 @@ impl Pmem {
283284 Ok ( ( ) )
284285 }
285286
286- fn process_chain ( & self , head : DescriptorChain ) -> Result < ( ) , PmemError > {
287+ fn process_chain (
288+ & self ,
289+ head : DescriptorChain ,
290+ cached_result : & mut Option < i32 > ,
291+ ) -> Result < ( ) , PmemError > {
287292 // This is safe since we checked in the event handler that the device is activated.
288293 let active_state = self . device_state . active_state ( ) . unwrap ( ) ;
289294
@@ -312,21 +317,33 @@ impl Pmem {
312317 return Err ( PmemError :: Non4byteStatusDescriptor ( status_descriptor. len ) ) ;
313318 }
314319
315- let mut result = SUCCESS ;
316- // SAFETY: We are calling the system call with valid arguments and checking the returned
317- // value
318- unsafe {
319- let ret = libc:: msync (
320- self . mmap_ptr as * mut libc:: c_void ,
321- u64_to_usize ( self . file_len ) ,
322- libc:: MS_SYNC ,
323- ) ;
324- if ret < 0 {
325- error ! ( "pmem: Unable to msync the file. Error: {}" , ret) ;
326- result = FAILURE ;
320+ // Since there is only 1 type of request pmem device supports,
321+ // we treat single notification from the guest as a single request
322+ // and reuse cached result of `msync` from first valid descriptor
323+ // for all following descriptors.
324+ if let Some ( result) = cached_result {
325+ active_state
326+ . mem
327+ . write_obj ( * result, status_descriptor. addr ) ?;
328+ } else {
329+ let mut status = SUCCESS ;
330+ // SAFETY: We are calling the system call with valid arguments and checking the returned
331+ // value
332+ unsafe {
333+ let ret = libc:: msync (
334+ self . mmap_ptr as * mut libc:: c_void ,
335+ u64_to_usize ( self . file_len ) ,
336+ libc:: MS_SYNC ,
337+ ) ;
338+ if ret < 0 {
339+ error ! ( "pmem: Unable to msync the file. Error: {}" , ret) ;
340+ status = FAILURE ;
341+ }
327342 }
343+ * cached_result = Some ( status) ;
344+
345+ active_state. mem . write_obj ( status, status_descriptor. addr ) ?;
328346 }
329- active_state. mem . write_obj ( result, status_descriptor. addr ) ?;
330347 Ok ( ( ) )
331348 }
332349
@@ -501,8 +518,28 @@ mod tests {
501518 vq. used . idx . set ( 0 ) ;
502519 vq. avail . idx . set ( 1 ) ;
503520 let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
504- pmem. process_chain ( head) . unwrap ( ) ;
521+ let mut result = None ;
522+ pmem. process_chain ( head, & mut result) . unwrap ( ) ;
505523 assert_eq ! ( mem. read_obj:: <u32 >( GuestAddress ( 0x2000 ) ) . unwrap( ) , 0 ) ;
524+ assert ! ( result. is_some( ) ) ;
525+ }
526+
527+ // Valid request cached value reuse
528+ {
529+ vq. avail . ring [ 0 ] . set ( 0 ) ;
530+ vq. dtable [ 0 ] . set ( 0x1000 , 4 , VIRTQ_DESC_F_NEXT , 1 ) ;
531+ vq. avail . ring [ 1 ] . set ( 1 ) ;
532+ vq. dtable [ 1 ] . set ( 0x2000 , 4 , VIRTQ_DESC_F_WRITE , 0 ) ;
533+ mem. write_obj :: < u32 > ( 0 , GuestAddress ( 0x1000 ) ) . unwrap ( ) ;
534+ mem. write_obj :: < u32 > ( 0x69 , GuestAddress ( 0x2000 ) ) . unwrap ( ) ;
535+
536+ pmem. queues [ 0 ] = vq. create_queue ( ) ;
537+ vq. used . idx . set ( 0 ) ;
538+ vq. avail . idx . set ( 1 ) ;
539+ let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
540+ let mut result = Some ( 0x69 ) ;
541+ pmem. process_chain ( head, & mut result) . unwrap ( ) ;
542+ assert_eq ! ( mem. read_obj:: <u32 >( GuestAddress ( 0x2000 ) ) . unwrap( ) , 0x69 ) ;
506543 }
507544
508545 // Invalid request type
@@ -516,7 +553,7 @@ mod tests {
516553 vq. avail . idx . set ( 1 ) ;
517554 let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
518555 assert ! ( matches!(
519- pmem. process_chain( head) . unwrap_err( ) ,
556+ pmem. process_chain( head, & mut None ) . unwrap_err( ) ,
520557 PmemError :: UnknownRequestType ( 0x69 ) ,
521558 ) ) ;
522559 }
@@ -532,7 +569,7 @@ mod tests {
532569 vq. avail . idx . set ( 1 ) ;
533570 let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
534571 assert ! ( matches!(
535- pmem. process_chain( head) . unwrap_err( ) ,
572+ pmem. process_chain( head, & mut None ) . unwrap_err( ) ,
536573 PmemError :: DescriptorChainTooShort ,
537574 ) ) ;
538575 }
@@ -550,7 +587,7 @@ mod tests {
550587 vq. avail . idx . set ( 1 ) ;
551588 let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
552589 assert ! ( matches!(
553- pmem. process_chain( head) . unwrap_err( ) ,
590+ pmem. process_chain( head, & mut None ) . unwrap_err( ) ,
554591 PmemError :: WriteOnlyDescriptor ,
555592 ) ) ;
556593 }
@@ -568,7 +605,7 @@ mod tests {
568605 vq. avail . idx . set ( 1 ) ;
569606 let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
570607 assert ! ( matches!(
571- pmem. process_chain( head) . unwrap_err( ) ,
608+ pmem. process_chain( head, & mut None ) . unwrap_err( ) ,
572609 PmemError :: ReadOnlyDescriptor ,
573610 ) ) ;
574611 }
@@ -584,7 +621,7 @@ mod tests {
584621 vq. avail . idx . set ( 1 ) ;
585622 let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
586623 assert ! ( matches!(
587- pmem. process_chain( head) . unwrap_err( ) ,
624+ pmem. process_chain( head, & mut None ) . unwrap_err( ) ,
588625 PmemError :: Non4byteHeadDescriptor ( 0x69 ) ,
589626 ) ) ;
590627 }
@@ -603,7 +640,7 @@ mod tests {
603640 vq. avail . idx . set ( 1 ) ;
604641 let head = pmem. queues [ 0 ] . pop ( ) . unwrap ( ) . unwrap ( ) ;
605642 assert ! ( matches!(
606- pmem. process_chain( head) . unwrap_err( ) ,
643+ pmem. process_chain( head, & mut None ) . unwrap_err( ) ,
607644 PmemError :: Non4byteStatusDescriptor ( 0x69 ) ,
608645 ) ) ;
609646 }
0 commit comments