@@ -115,7 +115,8 @@ pub mod vstate;
115115pub mod initrd;
116116
117117use std:: collections:: HashMap ;
118- use std:: io;
118+ use std:: io:: { self , Read , Write } ;
119+ use std:: os:: fd:: RawFd ;
119120use std:: os:: unix:: io:: AsRawFd ;
120121use std:: os:: unix:: net:: UnixStream ;
121122use std:: sync:: mpsc:: RecvTimeoutError ;
@@ -128,6 +129,7 @@ use devices::acpi::vmgenid::VmGenIdError;
128129use event_manager:: { EventManager as BaseEventManager , EventOps , Events , MutEventSubscriber } ;
129130use seccomp:: BpfProgram ;
130131use userfaultfd:: Uffd ;
132+ use vm_memory:: GuestAddress ;
131133use vmm_sys_util:: epoll:: EventSet ;
132134use vmm_sys_util:: eventfd:: EventFd ;
133135use vmm_sys_util:: terminal:: Terminal ;
@@ -147,15 +149,17 @@ use crate::devices::virtio::block::device::Block;
147149use crate :: devices:: virtio:: net:: Net ;
148150use crate :: devices:: virtio:: { TYPE_BALLOON , TYPE_BLOCK , TYPE_NET } ;
149151use crate :: logger:: { METRICS , MetricsError , error, info, warn} ;
150- use crate :: persist:: { MicrovmState , MicrovmStateError , VmInfo } ;
152+ use crate :: persist:: { FaultReply , FaultRequest , MicrovmState , MicrovmStateError , VmInfo } ;
151153use crate :: rate_limiter:: BucketUpdate ;
152154use crate :: snapshot:: Persist ;
153155use crate :: vmm_config:: instance_info:: { InstanceInfo , VmState } ;
154- use crate :: vstate:: memory:: { GuestMemory , GuestMemoryMmap , GuestMemoryRegion } ;
156+ use crate :: vstate:: memory:: {
157+ GuestMemory , GuestMemoryExtension , GuestMemoryMmap , GuestMemoryRegion ,
158+ } ;
155159use crate :: vstate:: vcpu:: VcpuState ;
156160pub use crate :: vstate:: vcpu:: { Vcpu , VcpuConfig , VcpuEvent , VcpuHandle , VcpuResponse } ;
157- use crate :: vstate:: vm:: UserfaultChannel ;
158161pub use crate :: vstate:: vm:: Vm ;
162+ use crate :: vstate:: vm:: { UserfaultChannel , UserfaultChannelError , UserfaultData } ;
159163
160164/// Shorthand type for the EventManager flavour used by Firecracker.
161165pub type EventManager = BaseEventManager < Arc < Mutex < dyn MutEventSubscriber > > > ;
@@ -803,6 +807,168 @@ impl Vmm {
803807 self . shutdown_exit_code = Some ( exit_code) ;
804808 }
805809
810+ fn active_event_in_userfault_channel (
811+ & self ,
812+ source : RawFd ,
813+ event_set : EventSet ,
814+ ) -> Option < usize > {
815+ if let Some ( userfault_channels) = & self . userfault_channels {
816+ userfault_channels. iter ( ) . position ( |channel| {
817+ let receiver = & channel. receiver ;
818+ source == receiver. as_raw_fd ( ) && event_set == EventSet :: IN
819+ } )
820+ } else {
821+ None
822+ }
823+ }
824+
825+ fn process_userfault_channels ( & mut self , vcpu : usize ) {
826+ loop {
827+ match self
828+ . userfault_channels
829+ . as_mut ( )
830+ . expect ( "Userfault channels must be set" ) [ vcpu]
831+ . recv ( )
832+ {
833+ Ok ( userfault_data) => {
834+ let offset = self
835+ . vm
836+ . guest_memory ( )
837+ . gpa_to_offset ( GuestAddress ( userfault_data. gpa ) )
838+ . unwrap ( ) ;
839+
840+ let fault_request = FaultRequest {
841+ vcpu : vcpu. try_into ( ) . expect ( "Invalid vCPU index" ) ,
842+ offset,
843+ flags : userfault_data. flags ,
844+ token : None ,
845+ } ;
846+ let fault_request_json = serde_json:: to_string ( & fault_request) . unwrap ( ) ;
847+
848+ let written = self
849+ . uffd_socket
850+ . as_ref ( )
851+ . unwrap ( )
852+ . write ( fault_request_json. as_bytes ( ) )
853+ . unwrap ( ) ;
854+
855+ if written != fault_request_json. len ( ) {
856+ panic ! (
857+ "Failed to write the entire fault request to the uffd socket: \
858+ expected {}, written {}",
859+ fault_request_json. len( ) ,
860+ written
861+ ) ;
862+ }
863+ }
864+ Err ( ref e) => match e {
865+ UserfaultChannelError :: IO ( io_e) if io_e. kind ( ) == io:: ErrorKind :: WouldBlock => {
866+ break ;
867+ }
868+ _ => panic ! ( "Error receiving userfault data: {}" , e) ,
869+ } ,
870+ }
871+ }
872+ }
873+
874+ fn active_event_in_uffd_socket ( & self , source : RawFd , event_set : EventSet ) -> bool {
875+ if let Some ( uffd_socket) = & self . uffd_socket {
876+ uffd_socket. as_raw_fd ( ) == source && event_set == EventSet :: IN
877+ } else {
878+ false
879+ }
880+ }
881+
882+ fn process_uffd_socket ( & mut self ) {
883+ const BUFFER_SIZE : usize = 4096 ;
884+
885+ let stream = self . uffd_socket . as_mut ( ) . expect ( "Uffd socket is not set" ) ;
886+
887+ let mut buffer = [ 0u8 ; BUFFER_SIZE ] ;
888+ let mut current_pos = 0 ;
889+ let mut exit_loop = false ;
890+
891+ loop {
892+ if current_pos < BUFFER_SIZE {
893+ match stream. read ( & mut buffer[ current_pos..] ) {
894+ Ok ( 0 ) => break ,
895+ Ok ( n) => current_pos += n,
896+ Err ( e) if e. kind ( ) == io:: ErrorKind :: WouldBlock => {
897+ if exit_loop {
898+ break ;
899+ }
900+ }
901+ Err ( e) => panic ! ( "Read error: {}" , e) ,
902+ }
903+
904+ exit_loop = false ;
905+ }
906+
907+ let mut parser = serde_json:: Deserializer :: from_slice ( & buffer[ ..current_pos] )
908+ . into_iter :: < FaultReply > ( ) ;
909+ let mut total_consumed = 0 ;
910+ let mut needs_more = false ;
911+
912+ while let Some ( result) = parser. next ( ) {
913+ match result {
914+ Ok ( fault_reply) => {
915+ let gpa = self
916+ . vm
917+ . common
918+ . guest_memory
919+ . offset_to_gpa ( fault_reply. offset )
920+ . expect ( "Failed to convert offset to GPA" ) ;
921+
922+ let userfaultfd_data = UserfaultData {
923+ flags : fault_reply. flags ,
924+ gpa : gpa. 0 ,
925+ size : fault_reply. len ,
926+ } ;
927+
928+ let vcpu = fault_reply. vcpu . expect ( "vCPU must be set" ) ;
929+
930+ self . userfault_channels
931+ . as_mut ( )
932+ . expect ( "userfault_channels are not set" )
933+ . get_mut ( vcpu as usize )
934+ . expect ( "Invalid vcpu index" )
935+ . send ( userfaultfd_data)
936+ . expect ( "Failed to send userfault data" ) ;
937+
938+ total_consumed = parser. byte_offset ( ) ;
939+ }
940+ Err ( e) if e. is_eof ( ) => {
941+ needs_more = true ;
942+ break ;
943+ }
944+ Err ( e) => {
945+ println ! (
946+ "Buffer content: {:?}" ,
947+ std:: str :: from_utf8( & buffer[ ..current_pos] )
948+ ) ;
949+ panic ! ( "Invalid JSON: {}" , e) ;
950+ }
951+ }
952+ }
953+
954+ if total_consumed > 0 {
955+ buffer. copy_within ( total_consumed..current_pos, 0 ) ;
956+ current_pos -= total_consumed;
957+ }
958+
959+ if needs_more {
960+ continue ;
961+ }
962+
963+ // We consumed all data in the buffer, but the socket may have remaining unread data so
964+ // we attempt to read from it and exit the loop only if we confirm that nothing is in
965+ // there.
966+ if current_pos == 0 {
967+ exit_loop = true ;
968+ }
969+ }
970+ }
971+
806972 /// Gets a reference to kvm-ioctls Vm
807973 #[ cfg( feature = "gdb" ) ]
808974 pub fn vm ( & self ) -> & Vm {
@@ -909,14 +1075,34 @@ impl MutEventSubscriber for Vmm {
9091075 FcExitCode :: Ok
9101076 } ;
9111077 self . stop ( exit_code) ;
912- } else {
913- error ! ( "Spurious EventManager event for handler: Vmm" ) ;
1078+ }
1079+
1080+ if let Some ( vcpu) = self . active_event_in_userfault_channel ( source, event_set) {
1081+ self . process_userfault_channels ( vcpu) ;
1082+ }
1083+
1084+ if self . active_event_in_uffd_socket ( source, event_set) {
1085+ self . process_uffd_socket ( ) ;
9141086 }
9151087 }
9161088
9171089 fn init ( & mut self , ops : & mut EventOps ) {
9181090 if let Err ( err) = ops. add ( Events :: new ( & self . vcpus_exit_evt , EventSet :: IN ) ) {
9191091 error ! ( "Failed to register vmm exit event: {}" , err) ;
9201092 }
1093+
1094+ if let Some ( uffd_socket) = self . uffd_socket . as_ref ( ) {
1095+ if let Err ( err) = ops. add ( Events :: new ( uffd_socket, EventSet :: IN ) ) {
1096+ panic ! ( "Failed to register UFFD socket: {}" , err) ;
1097+ }
1098+ }
1099+
1100+ if let Some ( userfault_channels) = self . userfault_channels . as_ref ( ) {
1101+ for channel in userfault_channels {
1102+ if let Err ( err) = ops. add ( Events :: new ( & channel. receiver , EventSet :: IN ) ) {
1103+ panic ! ( "Failed to register userfault events: {}" , err) ;
1104+ }
1105+ }
1106+ }
9211107 }
9221108}
0 commit comments