@@ -18,7 +18,7 @@ use crate::ioctls::device::DeviceFd;
18
18
use crate :: ioctls:: device:: new_device;
19
19
use crate :: ioctls:: vcpu:: VcpuFd ;
20
20
use crate :: ioctls:: vcpu:: new_vcpu;
21
- use crate :: ioctls:: { KvmRunWrapper , Result } ;
21
+ use crate :: ioctls:: { KvmDirtyLogRing , KvmRunWrapper , Result } ;
22
22
use crate :: kvm_ioctls:: * ;
23
23
use vmm_sys_util:: errno;
24
24
use vmm_sys_util:: eventfd:: EventFd ;
@@ -59,6 +59,7 @@ impl From<NoDatamatch> for u64 {
59
59
pub struct VmFd {
60
60
vm : File ,
61
61
run_size : usize ,
62
+ dirty_ring_bytes : usize ,
62
63
}
63
64
64
65
impl VmFd {
@@ -1214,7 +1215,15 @@ impl VmFd {
1214
1215
1215
1216
let kvm_run_ptr = KvmRunWrapper :: mmap_from_fd ( & vcpu, self . run_size ) ?;
1216
1217
1217
- Ok ( new_vcpu ( vcpu, kvm_run_ptr) )
1218
+ let dirty_log_ring = {
1219
+ if self . dirty_ring_bytes > 0 {
1220
+ Some ( KvmDirtyLogRing :: mmap_from_fd ( & vcpu, self . dirty_ring_bytes ) ?)
1221
+ } else {
1222
+ None
1223
+ }
1224
+ } ;
1225
+
1226
+ Ok ( new_vcpu ( vcpu, kvm_run_ptr, dirty_log_ring) )
1218
1227
}
1219
1228
1220
1229
/// Creates a VcpuFd object from a vcpu RawFd.
@@ -1250,7 +1259,14 @@ impl VmFd {
1250
1259
// SAFETY: we trust the kernel and verified parameters
1251
1260
let vcpu = unsafe { File :: from_raw_fd ( fd) } ;
1252
1261
let kvm_run_ptr = KvmRunWrapper :: mmap_from_fd ( & vcpu, self . run_size ) ?;
1253
- Ok ( new_vcpu ( vcpu, kvm_run_ptr) )
1262
+ let dirty_log_ring = {
1263
+ if self . dirty_ring_bytes > 0 {
1264
+ Some ( KvmDirtyLogRing :: mmap_from_fd ( & vcpu, self . dirty_ring_bytes ) ?)
1265
+ } else {
1266
+ None
1267
+ }
1268
+ } ;
1269
+ Ok ( new_vcpu ( vcpu, kvm_run_ptr, dirty_log_ring) )
1254
1270
}
1255
1271
1256
1272
/// Creates an emulated device in the kernel.
@@ -1915,6 +1931,112 @@ impl VmFd {
1915
1931
Ok ( ( ) )
1916
1932
}
1917
1933
1934
+ /// Enables KVM's dirty log ring for new vCPUs created on this VM. Checks required capabilities and returns
1935
+ /// `true` if the ring needs to be used together with a backup bitmap `KVM_GET_DIRTY_LOG`. Takes optional
1936
+ /// dirty ring size as bytes, if not supplied, will use maximum supported dirty ring size. Enabling the dirty
1937
+ /// log ring is only allowed before any vCPU was created on the VmFd.
1938
+ /// # Arguments
1939
+ ///
1940
+ /// * `bytes` - Size of the dirty log ring in bytes. Needs to be multiple of `std::mem::size_of::<kvm_dirty_gfn>()`
1941
+ /// and power of two.
1942
+ pub fn enable_dirty_log_ring ( & self , bytes : Option < i32 > ) -> Result < bool > {
1943
+ // Check if requested size is larger than 0
1944
+ if let Some ( sz) = bytes {
1945
+ if sz <= 0
1946
+ || !( sz as u32 ) . is_power_of_two ( )
1947
+ || ( sz as usize % std:: mem:: size_of :: < kvm_dirty_gfn > ( ) == 0 )
1948
+ {
1949
+ return Err ( errno:: Error :: new ( libc:: EINVAL ) ) ;
1950
+ }
1951
+ }
1952
+
1953
+ let ( dirty_ring_cap, max_bytes, bitmap) = {
1954
+ // Check if KVM_CAP_DIRTY_LOG_RING_ACQ_REL is available, enable if possible
1955
+ let acq_rel_sz = self . check_extension_raw ( KVM_CAP_DIRTY_LOG_RING_ACQ_REL . into ( ) ) ;
1956
+ if acq_rel_sz > 0 {
1957
+ if self . check_extension_raw ( KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP . into ( ) ) != 0 {
1958
+ ( KVM_CAP_DIRTY_LOG_RING_ACQ_REL , acq_rel_sz, true )
1959
+ } else {
1960
+ ( KVM_CAP_DIRTY_LOG_RING_ACQ_REL , acq_rel_sz, false )
1961
+ }
1962
+ } else {
1963
+ let sz = self . check_extension_raw ( KVM_CAP_DIRTY_LOG_RING . into ( ) ) ;
1964
+ if sz > 0 {
1965
+ ( KVM_CAP_DIRTY_LOG_RING , sz, false )
1966
+ } else {
1967
+ ( 0 , 0 , false )
1968
+ }
1969
+ }
1970
+ } ;
1971
+
1972
+ #[ cfg( target_arch = "aarch64" ) ]
1973
+ if dirty_ring_cap != KVM_CAP_DIRTY_LOG_RING_ACQ_REL {
1974
+ // Can not use dirty log ring on aarch64 without _ACQ_REL
1975
+ return Err ( errno:: Error :: new ( libc:: EOPNOTSUPP ) ) ;
1976
+ }
1977
+
1978
+ if dirty_ring_cap == 0 {
1979
+ // Neither KVM_CAP_DIRTY_LOG_RING nor KVM_CAP_DIRTY_LOG_RING_ACQ_REL are available
1980
+ return Err ( errno:: Error :: new ( libc:: EOPNOTSUPP ) ) ;
1981
+ }
1982
+
1983
+ let cap_ring_size = bytes. unwrap_or ( max_bytes) ;
1984
+
1985
+ // Check if supplied size is larger than what the kernel supports
1986
+ if cap_ring_size > max_bytes {
1987
+ return Err ( errno:: Error :: new ( libc:: EINVAL ) ) ;
1988
+ }
1989
+
1990
+ // Enable dirty rings with _ACQ_REL if supported, or without otherwise
1991
+ let ar_ring_cap = kvm_enable_cap {
1992
+ cap : dirty_ring_cap,
1993
+ args : [ cap_ring_size as u64 , 0 , 0 , 0 ] ,
1994
+ ..Default :: default ( )
1995
+ } ;
1996
+
1997
+ // Enable the ring cap first
1998
+ self . enable_cap ( & ar_ring_cap) ?;
1999
+
2000
+ if bitmap {
2001
+ let with_bitmap_cap = kvm_enable_cap {
2002
+ cap : KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP ,
2003
+ ..Default :: default ( )
2004
+ } ;
2005
+
2006
+ // Enable backup bitmap
2007
+ self . enable_cap ( & with_bitmap_cap) ?;
2008
+ }
2009
+
2010
+ Ok ( bitmap)
2011
+ }
2012
+
2013
+ /// Resets all vCPU's dirty log rings. This notifies the kernel that pages have been harvested
2014
+ /// from the dirty ring and the corresponding pages can be reprotected.
2015
+ ///
2016
+ /// # Example
2017
+ ///
2018
+ /// ```rust
2019
+ /// # extern crate kvm_ioctls;
2020
+ /// # use kvm_ioctls::{Cap, Kvm};
2021
+ /// let kvm = Kvm::new().unwrap();
2022
+ /// let vm = kvm.create_vm().unwrap();
2023
+ /// vm.enable_dirty_log_ring(None).unwrap();
2024
+ /// if kvm.check_extension(Cap::DirtyLogRing) {
2025
+ /// vm.reset_dirty_rings().unwrap();
2026
+ /// }
2027
+ /// ```
2028
+ ///
2029
+ pub fn reset_dirty_rings ( & self ) -> Result < c_int > {
2030
+ // SAFETY: Safe because we know that our file is a KVM fd and that the request is one of
2031
+ // the ones defined by kernel.
2032
+ let ret = unsafe { ioctl ( self , KVM_RESET_DIRTY_RINGS ( ) ) } ;
2033
+ if ret < 0 {
2034
+ Err ( errno:: Error :: last ( ) )
2035
+ } else {
2036
+ Ok ( ret)
2037
+ }
2038
+ }
2039
+
1918
2040
/// Sets a specified piece of vm configuration and/or state.
1919
2041
///
1920
2042
/// See the documentation for `KVM_SET_DEVICE_ATTR` in
@@ -2011,7 +2133,11 @@ impl VmFd {
2011
2133
/// `create_vm` from `Kvm`. The function cannot be part of the `VmFd` implementation because
2012
2134
/// then it would be exported with the public `VmFd` interface.
2013
2135
pub fn new_vmfd ( vm : File , run_size : usize ) -> VmFd {
2014
- VmFd { vm, run_size }
2136
+ VmFd {
2137
+ vm,
2138
+ run_size,
2139
+ dirty_ring_bytes : 0 ,
2140
+ }
2015
2141
}
2016
2142
2017
2143
impl AsRawFd for VmFd {
@@ -2601,6 +2727,7 @@ mod tests {
2601
2727
let faulty_vm_fd = VmFd {
2602
2728
vm : unsafe { File :: from_raw_fd ( -2 ) } ,
2603
2729
run_size : 0 ,
2730
+ dirty_ring_bytes : 0 ,
2604
2731
} ;
2605
2732
2606
2733
let invalid_mem_region = kvm_userspace_memory_region {
0 commit comments