@@ -93,7 +93,7 @@ pub struct MicrovmState {
93
93
/// E.g. Guest memory contents for a region of `size` bytes can be found in the
94
94
/// backend at `offset` bytes from the beginning, and should be copied/populated
95
95
/// into `base_host_address`.
96
- #[ derive( Clone , Debug , Serialize ) ]
96
+ #[ derive( Clone , Debug , Serialize , Deserialize , PartialEq , Eq ) ]
97
97
pub struct GuestRegionUffdMapping {
98
98
/// Base host virtual address where the guest memory contents for this
99
99
/// region should be copied/populated.
@@ -516,7 +516,8 @@ fn guest_memory_from_uffd(
516
516
enable_balloon : bool ,
517
517
huge_pages : HugePageConfig ,
518
518
) -> Result < ( GuestMemoryMmap , Option < Uffd > ) , GuestMemoryFromUffdError > {
519
- let guest_memory = GuestMemoryMmap :: from_state ( None , mem_state, track_dirty_pages, huge_pages) ?;
519
+ let ( guest_memory, backend_mappings) =
520
+ create_guest_memory ( mem_state, track_dirty_pages, huge_pages) ?;
520
521
521
522
let mut uffd_builder = UffdBuilder :: new ( ) ;
522
523
@@ -533,24 +534,43 @@ fn guest_memory_from_uffd(
533
534
. create ( )
534
535
. map_err ( GuestMemoryFromUffdError :: Create ) ?;
535
536
537
+ for mem_region in guest_memory. iter ( ) {
538
+ uffd. register ( mem_region. as_ptr ( ) . cast ( ) , mem_region. size ( ) as _ )
539
+ . map_err ( GuestMemoryFromUffdError :: Register ) ?;
540
+ }
541
+
542
+ send_uffd_handshake ( mem_uds_path, & backend_mappings, & uffd) ?;
543
+
544
+ Ok ( ( guest_memory, Some ( uffd) ) )
545
+ }
546
+
547
+ fn create_guest_memory (
548
+ mem_state : & GuestMemoryState ,
549
+ track_dirty_pages : bool ,
550
+ huge_pages : HugePageConfig ,
551
+ ) -> Result < ( GuestMemoryMmap , Vec < GuestRegionUffdMapping > ) , GuestMemoryFromUffdError > {
552
+ let guest_memory = GuestMemoryMmap :: from_state ( None , mem_state, track_dirty_pages, huge_pages) ?;
536
553
let mut backend_mappings = Vec :: with_capacity ( guest_memory. num_regions ( ) ) ;
537
554
for ( mem_region, state_region) in guest_memory. iter ( ) . zip ( mem_state. regions . iter ( ) ) {
538
- let host_base_addr = mem_region. as_ptr ( ) ;
539
- let size = mem_region. size ( ) ;
540
-
541
- uffd. register ( host_base_addr. cast ( ) , size as _ )
542
- . map_err ( GuestMemoryFromUffdError :: Register ) ?;
543
555
backend_mappings. push ( GuestRegionUffdMapping {
544
- base_host_virt_addr : host_base_addr as u64 ,
545
- size,
556
+ base_host_virt_addr : mem_region . as_ptr ( ) as u64 ,
557
+ size : mem_region . size ( ) ,
546
558
offset : state_region. offset ,
547
559
page_size_kib : huge_pages. page_size_kib ( ) ,
548
560
} ) ;
549
561
}
550
562
563
+ Ok ( ( guest_memory, backend_mappings) )
564
+ }
565
+
566
+ fn send_uffd_handshake (
567
+ mem_uds_path : & Path ,
568
+ backend_mappings : & [ GuestRegionUffdMapping ] ,
569
+ uffd : & impl AsRawFd ,
570
+ ) -> Result < ( ) , GuestMemoryFromUffdError > {
551
571
// This is safe to unwrap() because we control the contents of the vector
552
572
// (i.e GuestRegionUffdMapping entries).
553
- let backend_mappings = serde_json:: to_string ( & backend_mappings) . unwrap ( ) ;
573
+ let backend_mappings = serde_json:: to_string ( backend_mappings) . unwrap ( ) ;
554
574
555
575
let socket = UnixStream :: connect ( mem_uds_path) ?;
556
576
socket. send_with_fd (
@@ -588,11 +608,13 @@ fn guest_memory_from_uffd(
588
608
uffd. as_raw_fd ( ) ,
589
609
) ?;
590
610
591
- Ok ( ( guest_memory , Some ( uffd ) ) )
611
+ Ok ( ( ) )
592
612
}
593
613
594
614
#[ cfg( test) ]
595
615
mod tests {
616
+ use std:: os:: unix:: net:: UnixListener ;
617
+
596
618
use utils:: tempfile:: TempFile ;
597
619
598
620
use super :: * ;
@@ -607,6 +629,7 @@ mod tests {
607
629
use crate :: vmm_config:: balloon:: BalloonDeviceConfig ;
608
630
use crate :: vmm_config:: net:: NetworkInterfaceConfig ;
609
631
use crate :: vmm_config:: vsock:: tests:: default_config;
632
+ use crate :: vstate:: memory:: GuestMemoryRegionState ;
610
633
use crate :: Vmm ;
611
634
612
635
fn default_vmm_with_devices ( ) -> Vmm {
@@ -700,4 +723,65 @@ mod tests {
700
723
microvm_state. device_states
701
724
)
702
725
}
726
+
727
+ #[ test]
728
+ fn test_create_guest_memory ( ) {
729
+ let mem_state = GuestMemoryState {
730
+ regions : vec ! [ GuestMemoryRegionState {
731
+ base_address: 0 ,
732
+ size: 0x20000 ,
733
+ offset: 0x10000 ,
734
+ } ] ,
735
+ } ;
736
+
737
+ let ( _, uffd_regions) =
738
+ create_guest_memory ( & mem_state, false , HugePageConfig :: None ) . unwrap ( ) ;
739
+
740
+ assert_eq ! ( uffd_regions. len( ) , 1 ) ;
741
+ assert_eq ! ( uffd_regions[ 0 ] . size, 0x20000 ) ;
742
+ assert_eq ! ( uffd_regions[ 0 ] . offset, 0x10000 ) ;
743
+ assert_eq ! (
744
+ uffd_regions[ 0 ] . page_size_kib,
745
+ HugePageConfig :: None . page_size_kib( )
746
+ ) ;
747
+ }
748
+
749
+ #[ test]
750
+ fn test_send_uffd_handshake ( ) {
751
+ let uffd_regions = vec ! [
752
+ GuestRegionUffdMapping {
753
+ base_host_virt_addr: 0 ,
754
+ size: 0x100000 ,
755
+ offset: 0 ,
756
+ page_size_kib: HugePageConfig :: None . page_size_kib( ) ,
757
+ } ,
758
+ GuestRegionUffdMapping {
759
+ base_host_virt_addr: 0x100000 ,
760
+ size: 0x200000 ,
761
+ offset: 0 ,
762
+ page_size_kib: HugePageConfig :: Hugetlbfs2M . page_size_kib( ) ,
763
+ } ,
764
+ ] ;
765
+
766
+ let uds_path = TempFile :: new ( ) . unwrap ( ) ;
767
+ let uds_path = uds_path. as_path ( ) ;
768
+ std:: fs:: remove_file ( uds_path) . unwrap ( ) ;
769
+
770
+ let listener = UnixListener :: bind ( uds_path) . expect ( "Cannot bind to socket path" ) ;
771
+
772
+ send_uffd_handshake ( uds_path, & uffd_regions, & std:: io:: stdin ( ) ) . unwrap ( ) ;
773
+
774
+ let ( stream, _) = listener. accept ( ) . expect ( "Cannot listen on UDS socket" ) ;
775
+
776
+ let mut message_buf = vec ! [ 0u8 ; 1024 ] ;
777
+ let ( bytes_read, _) = stream
778
+ . recv_with_fd ( & mut message_buf[ ..] )
779
+ . expect ( "Cannot recv_with_fd" ) ;
780
+ message_buf. resize ( bytes_read, 0 ) ;
781
+
782
+ let deserialized: Vec < GuestRegionUffdMapping > =
783
+ serde_json:: from_slice ( & message_buf) . unwrap ( ) ;
784
+
785
+ assert_eq ! ( uffd_regions, deserialized) ;
786
+ }
703
787
}
0 commit comments