@@ -25,7 +25,9 @@ use crate::vmm_config::balloon::{
2525use crate :: vmm_config:: boot_source:: { BootSourceConfig , BootSourceConfigError } ;
2626use crate :: vmm_config:: drive:: { BlockDeviceConfig , BlockDeviceUpdateConfig , DriveError } ;
2727use crate :: vmm_config:: entropy:: { EntropyDeviceConfig , EntropyDeviceError } ;
28- use crate :: vmm_config:: instance_info:: { InstanceInfo , MemoryMappingsResponse , MemoryResponse } ;
28+ use crate :: vmm_config:: instance_info:: {
29+ InstanceInfo , MemoryDirty , MemoryMappingsResponse , MemoryResponse , VmState ,
30+ } ;
2931use crate :: vmm_config:: machine_config:: { MachineConfig , MachineConfigUpdate , VmConfigError } ;
3032use crate :: vmm_config:: metrics:: { MetricsConfig , MetricsConfigError } ;
3133use crate :: vmm_config:: mmds:: { MmdsConfig , MmdsConfigError } ;
@@ -69,6 +71,8 @@ pub enum VmmAction {
6971 GetMemoryMappings ,
7072 /// Get memory info (resident and empty pages).
7173 GetMemory ,
74+ /// Get guest memory dirty pages information
75+ GetMemoryDirty ,
7276 /// Get microVM version.
7377 GetVmmVersion ,
7478 /// Flush the metrics. This action can only be called after the logger has been configured.
@@ -168,6 +172,8 @@ pub enum VmmActionError {
168172 OperationNotSupportedPostBoot ,
169173 /// The requested operation is not supported before starting the microVM.
170174 OperationNotSupportedPreBoot ,
175+ /// The requested operation is not supported while the microVM is running.
176+ OperationNotSupportedWhileRunning ,
171177 /// Start microvm error: {0}
172178 StartMicrovm ( #[ from] StartMicrovmError ) ,
173179 /// Vsock config error: {0}
@@ -197,6 +203,8 @@ pub enum VmmData {
197203 MemoryMappings ( MemoryMappingsResponse ) ,
198204 /// Memory info (resident and empty pages).
199205 Memory ( MemoryResponse ) ,
206+ /// The guest memory dirty pages information
207+ MemoryDirty ( MemoryDirty ) ,
200208 /// The microVM version.
201209 VmmVersion ( String ) ,
202210}
@@ -427,7 +435,9 @@ impl<'a> PrebootApiController<'a> {
427435 & self . vm_resources . vm_config ,
428436 ) ) ) ,
429437 GetVmInstanceInfo => Ok ( VmmData :: InstanceInformation ( self . instance_info . clone ( ) ) ) ,
430- GetMemoryMappings | GetMemory => Err ( VmmActionError :: OperationNotSupportedPreBoot ) ,
438+ GetMemoryMappings | GetMemory | GetMemoryDirty => {
439+ Err ( VmmActionError :: OperationNotSupportedPreBoot )
440+ }
431441 GetVmmVersion => Ok ( VmmData :: VmmVersion ( self . instance_info . vmm_version . clone ( ) ) ) ,
432442 InsertBlockDevice ( config) => self . insert_block_device ( config) ,
433443 InsertNetworkDevice ( config) => self . insert_net_device ( config) ,
@@ -680,6 +690,7 @@ impl RuntimeApiController {
680690 empty : empty_bitmap,
681691 } ) )
682692 }
693+ GetMemoryDirty => self . get_dirty_memory_info ( ) ,
683694 GetVmmVersion => Ok ( VmmData :: VmmVersion (
684695 self . vmm . lock ( ) . expect ( "Poisoned lock" ) . version ( ) ,
685696 ) ) ,
@@ -779,6 +790,28 @@ impl RuntimeApiController {
779790 . map_err ( VmmActionError :: InternalVmm )
780791 }
781792
793+ /// Get dirty pages information for guest memory
794+ fn get_dirty_memory_info ( & self ) -> Result < VmmData , VmmActionError > {
795+ let start_us = get_time_us ( ClockType :: Monotonic ) ;
796+ let vmm = self . vmm . lock ( ) . expect ( "Poisoned lock" ) ;
797+
798+ // Dirty page tracking via pagemap requires the VM to be paused so that guest
799+ // pages are not modified while we are reading the pagemap.
800+ if vmm. instance_info . state != VmState :: Paused {
801+ return Err ( VmmActionError :: OperationNotSupportedWhileRunning ) ;
802+ }
803+
804+ let page_size = self . vm_resources . vm_config . huge_pages . page_size_kib ( ) ;
805+ let bitmap = vmm
806+ . get_dirty_memory ( page_size)
807+ . map_err ( VmmActionError :: InternalVmm ) ?;
808+
809+ let elapsed_time_us = get_time_us ( ClockType :: Monotonic ) - start_us;
810+ info ! ( "'get dirty memory' VMM action took {elapsed_time_us} us." ) ;
811+
812+ Ok ( VmmData :: MemoryDirty ( MemoryDirty { bitmap } ) )
813+ }
814+
782815 fn create_snapshot (
783816 & mut self ,
784817 create_params : & CreateSnapshotParams ,
0 commit comments