@@ -231,8 +231,8 @@ pub struct FaultRequest {
231231 pub offset : u64 ,
232232 /// Flags
233233 pub flags : u64 ,
234- /// Async PF token
235- pub token : Option < u32 > ,
234+ /// Async PF GPA (set for APF fallback faults, None for sync faults)
235+ pub gpa : Option < u64 > ,
236236}
237237
238238impl FaultRequest {
@@ -242,7 +242,7 @@ impl FaultRequest {
242242 offset : self . offset ,
243243 len,
244244 flags : self . flags ,
245- token : self . token ,
245+ gpa : self . gpa ,
246246 zero : false ,
247247 }
248248 }
@@ -259,8 +259,8 @@ pub struct FaultReply {
259259 pub len : u64 ,
260260 /// Flags, must be copied from `FaultRequest`, otherwise 0
261261 pub flags : u64 ,
262- /// Async PF token , must be copied from `FaultRequest`, otherwise None
263- pub token : Option < u32 > ,
262+ /// Async PF GPA , must be copied from `FaultRequest`, otherwise None
263+ pub gpa : Option < u64 > ,
264264 /// Whether the populated pages are zero pages
265265 pub zero : bool ,
266266}
@@ -423,6 +423,17 @@ impl UffdHandler {
423423 }
424424 }
425425
426+ /// Convert a guest physical address to an offset in the backing memory file.
427+ #[ inline]
428+ pub fn gpa_to_offset ( & self , gpa : u64 ) -> Option < usize > {
429+ for region in & self . mem_regions {
430+ if region. gpa_start <= gpa && gpa < region. gpa_start + region. size as u64 {
431+ return Some ( ( gpa - region. gpa_start + region. offset ) as usize ) ;
432+ }
433+ }
434+ None
435+ }
436+
426437 pub fn read_event ( & mut self ) -> Result < Option < Event > , Error > {
427438 self . uffd . read_event ( )
428439 }
@@ -733,6 +744,13 @@ impl Runtime {
733744 self . stream . write_all ( & encoded) . unwrap ( ) ;
734745 }
735746
747+ pub fn send_apf_fault_reply ( & mut self , fault_reply : FaultReply ) {
748+ let encoded = bitcode:: encode ( & fault_reply) ;
749+ let size = ( encoded. len ( ) as u32 ) . to_le_bytes ( ) ;
750+ self . apf_stream . write_all ( & size) . unwrap ( ) ;
751+ self . apf_stream . write_all ( & encoded) . unwrap ( ) ;
752+ }
753+
736754 pub fn construct_handler (
737755 stream : & UnixStream ,
738756 backing_memory : * mut u8 ,
@@ -857,6 +875,11 @@ impl Runtime {
857875
858876 let mut uffd_msg_iter =
859877 UffdMsgIterBitcode :: new ( self . stream . try_clone ( ) . expect ( "Failed to clone stream" ) ) ;
878+ let mut apf_msg_iter = UffdMsgIterBitcode :: new (
879+ self . apf_stream
880+ . try_clone ( )
881+ . expect ( "Failed to clone APF stream" ) ,
882+ ) ;
860883
861884 loop {
862885 let pollfd_ptr = pollfds. as_mut_ptr ( ) ;
@@ -879,52 +902,40 @@ impl Runtime {
879902 if fd. fd == stream_fd {
880903 for fault_request in uffd_msg_iter. by_ref ( ) {
881904 let page_size = self . handler . page_size ;
882-
905+ let offset = fault_request
906+ . gpa
907+ . and_then ( |gpa| self . handler . gpa_to_offset ( gpa) )
908+ . unwrap_or ( fault_request. offset as usize ) ;
883909 assert ! (
884- ( fault_request . offset as usize ) < self . handler. size( ) ,
910+ offset < self . handler. size( ) ,
885911 "received bogus offset from firecracker"
886912 ) ;
887-
888- pf_vcpu_event_dispatch (
889- & mut self . handler ,
890- fault_request. offset as usize ,
891- ) ;
892-
913+ pf_vcpu_event_dispatch ( & mut self . handler , offset) ;
893914 self . send_fault_reply ( fault_request. into_reply ( page_size as u64 ) ) ;
894915 }
895916 } else if fd. fd == apf_stream_fd {
896- // APF fallback path: fault requests over socket
897- for fault_request in uffd_msg_iter . by_ref ( ) {
917+ // APF fallback path: read from APF socket, reply on APF socket
918+ for fault_request in apf_msg_iter . by_ref ( ) {
898919 let page_size = self . handler . page_size ;
899-
920+ let offset = fault_request
921+ . gpa
922+ . and_then ( |gpa| self . handler . gpa_to_offset ( gpa) )
923+ . unwrap_or ( fault_request. offset as usize ) ;
900924 assert ! (
901- ( fault_request. offset as usize ) < self . handler. size( ) ,
902- "received bogus offset from firecracker"
903- ) ;
904-
905- pf_vcpu_event_dispatch (
906- & mut self . handler ,
907- fault_request. offset as usize ,
925+ offset < self . handler. size( ) ,
926+ "received bogus offset from APF handler"
908927 ) ;
909-
910- self . send_fault_reply ( fault_request. into_reply ( page_size as u64 ) ) ;
928+ pf_vcpu_event_dispatch ( & mut self . handler , offset ) ;
929+ self . send_apf_fault_reply ( fault_request. into_reply ( page_size as u64 ) ) ;
911930 }
912931 } else if let Some ( ctx) = self . exitless_vcpus . get_mut ( & fd. fd ) {
913932 // Exitless APF: drain notify ring and resolve pages
914933 ctx. drain_eventfd ( ) ;
915934 while let Some ( entry) = ctx. notify_ring ( ) . pop ( ) {
916- let gpa = entry. gpa ;
917- // Find the region and offset for this GPA
918- for region in & self . handler . mem_regions {
919- if region. gpa_start <= gpa
920- && gpa < region. gpa_start + region. size as u64
921- {
922- let offset = ( gpa - region. gpa_start + region. offset ) as usize ;
923- pf_vcpu_event_dispatch ( & mut self . handler , offset) ;
924- break ;
925- }
935+ if let Some ( offset) = self . handler . gpa_to_offset ( entry. gpa ) {
936+ pf_vcpu_event_dispatch ( & mut self . handler , offset) ;
926937 }
927- ctx. signal_ready ( gpa) ;
938+ ctx. signal_ready ( entry . gpa ) ;
928939 }
929940 } else {
930941 // Handle one of uffd page faults
@@ -977,6 +988,9 @@ mod tests {
977988 let ( apf_stream, _) = apf_listener
978989 . accept ( )
979990 . expect ( "Cannot listen on APF UDS socket" ) ;
991+ apf_stream
992+ . set_nonblocking ( true )
993+ . expect ( "Cannot set APF stream non-blocking" ) ;
980994 // Update runtime with actual runtime
981995 let runtime = uninit_runtime. write ( Runtime :: new ( stream, file, apf_stream) ) ;
982996 runtime. run ( |_: & mut UffdHandler | { } , |_: & mut UffdHandler , _: usize | { } ) ;
@@ -1024,7 +1038,7 @@ mod tests {
10241038 vcpu : 0 ,
10251039 offset : 0xDEAD_0000 , // way beyond 0x1000 handler size
10261040 flags : 0 ,
1027- token : None ,
1041+ gpa : None ,
10281042 } ;
10291043 let encoded = bitcode:: encode ( & bogus_request) ;
10301044 let size = ( encoded. len ( ) as u32 ) . to_le_bytes ( ) ;
0 commit comments