@@ -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,158 @@ 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 as _ ,
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+ self . uffd_socket
849+ . as_ref ( )
850+ . unwrap ( )
851+ . write ( fault_request_json. as_bytes ( ) )
852+ . unwrap ( ) ;
853+ }
854+ Err ( ref e) => match e {
855+ UserfaultChannelError :: IO ( io_e) if io_e. kind ( ) == io:: ErrorKind :: WouldBlock => {
856+ break ;
857+ }
858+ _ => panic ! ( "Error receiving userfault data: {}" , e) ,
859+ } ,
860+ }
861+ }
862+ }
863+
864+ fn active_event_in_uffd_socket ( & self , source : RawFd , event_set : EventSet ) -> bool {
865+ if let Some ( uffd_socket) = & self . uffd_socket {
866+ uffd_socket. as_raw_fd ( ) == source && event_set == EventSet :: IN
867+ } else {
868+ false
869+ }
870+ }
871+
872+ fn process_uffd_socket ( & mut self ) {
873+ const BUFFER_SIZE : usize = 4096 ;
874+
875+ let stream = self . uffd_socket . as_mut ( ) . expect ( "Uffd socket is not set" ) ;
876+
877+ let mut buffer = [ 0u8 ; BUFFER_SIZE ] ;
878+ let mut current_pos = 0 ;
879+ let mut exit_loop = false ;
880+
881+ loop {
882+ if current_pos < BUFFER_SIZE {
883+ match stream. read ( & mut buffer[ current_pos..] ) {
884+ Ok ( 0 ) => break ,
885+ Ok ( n) => current_pos += n,
886+ Err ( e) if e. kind ( ) == io:: ErrorKind :: WouldBlock => {
887+ if exit_loop {
888+ break ;
889+ }
890+ }
891+ Err ( e) => panic ! ( "Read error: {}" , e) ,
892+ }
893+
894+ exit_loop = false ;
895+ }
896+
897+ let mut parser = serde_json:: Deserializer :: from_slice ( & buffer[ ..current_pos] )
898+ . into_iter :: < FaultReply > ( ) ;
899+ let mut total_consumed = 0 ;
900+ let mut needs_more = false ;
901+
902+ while let Some ( result) = parser. next ( ) {
903+ match result {
904+ Ok ( fault_reply) => {
905+ let gpa = self
906+ . vm
907+ . common
908+ . guest_memory
909+ . offset_to_gpa ( fault_reply. offset )
910+ . expect ( "Failed to convert offset to GPA" ) ;
911+
912+ let userfaultfd_data = UserfaultData {
913+ flags : fault_reply. flags ,
914+ gpa : gpa. 0 ,
915+ size : fault_reply. len ,
916+ } ;
917+
918+ let vcpu = fault_reply. vcpu . expect ( "vCPU must be set" ) ;
919+
920+ self . userfault_channels
921+ . as_mut ( )
922+ . expect ( "userfault_channels are not set" )
923+ . get_mut ( vcpu as usize )
924+ . expect ( "Invalid vcpu index" )
925+ . send ( userfaultfd_data)
926+ . expect ( "Failed to send userfault data" ) ;
927+
928+ total_consumed = parser. byte_offset ( ) ;
929+ }
930+ Err ( e) if e. is_eof ( ) => {
931+ needs_more = true ;
932+ break ;
933+ }
934+ Err ( e) => {
935+ println ! (
936+ "Buffer content: {:?}" ,
937+ std:: str :: from_utf8( & buffer[ ..current_pos] )
938+ ) ;
939+ panic ! ( "Invalid JSON: {}" , e) ;
940+ }
941+ }
942+ }
943+
944+ if total_consumed > 0 {
945+ buffer. copy_within ( total_consumed..current_pos, 0 ) ;
946+ current_pos -= total_consumed;
947+ }
948+
949+ if needs_more {
950+ continue ;
951+ }
952+
953+ // We consumed all data in the buffer, but the socket may have remaining unread data so
954+ // we attempt to read from it and exit the loop only if we confirm that nothing is in
955+ // there.
956+ if current_pos == 0 {
957+ exit_loop = true ;
958+ }
959+ }
960+ }
961+
806962 /// Gets a reference to kvm-ioctls Vm
807963 #[ cfg( feature = "gdb" ) ]
808964 pub fn vm ( & self ) -> & Vm {
@@ -909,14 +1065,37 @@ impl MutEventSubscriber for Vmm {
9091065 FcExitCode :: Ok
9101066 } ;
9111067 self . stop ( exit_code) ;
912- } else {
913- error ! ( "Spurious EventManager event for handler: Vmm" ) ;
1068+ }
1069+
1070+ if let Some ( vcpu) = self . active_event_in_userfault_channel ( source, event_set) {
1071+ self . process_userfault_channels ( vcpu) ;
1072+ }
1073+
1074+ if self . active_event_in_uffd_socket ( source, event_set) {
1075+ self . process_uffd_socket ( ) ;
9141076 }
9151077 }
9161078
9171079 fn init ( & mut self , ops : & mut EventOps ) {
9181080 if let Err ( err) = ops. add ( Events :: new ( & self . vcpus_exit_evt , EventSet :: IN ) ) {
9191081 error ! ( "Failed to register vmm exit event: {}" , err) ;
9201082 }
1083+
1084+ if let Some ( uffd_socket) = self . uffd_socket . as_ref ( ) {
1085+ if let Err ( err) = ops. add ( Events :: new ( uffd_socket, EventSet :: IN ) ) {
1086+ panic ! ( "Failed to register UFFD socket: {}" , err) ;
1087+ }
1088+ }
1089+
1090+ if let Some ( userfault_channels) = self . userfault_channels . as_ref ( ) {
1091+ for cpu_idx in 0 ..userfault_channels. len ( ) {
1092+ if let Err ( err) = ops. add ( Events :: new (
1093+ & userfault_channels[ cpu_idx] . receiver ,
1094+ EventSet :: IN ,
1095+ ) ) {
1096+ panic ! ( "Failed to register userfault events: {}" , err) ;
1097+ }
1098+ }
1099+ }
9211100 }
9221101}
0 commit comments