@@ -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,108 @@ 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
+ #[ cfg( target_arch = "x86_64" ) ]
1943
+ pub fn enable_dirty_log_ring ( & self , bytes : Option < i32 > ) -> Result < bool > {
1944
+ // Check if requested size is larger than 0
1945
+ if let Some ( sz) = bytes {
1946
+ if sz <= 0
1947
+ || !( sz as u32 ) . is_power_of_two ( )
1948
+ || ( sz as usize % std:: mem:: size_of :: < kvm_dirty_gfn > ( ) == 0 )
1949
+ {
1950
+ return Err ( errno:: Error :: new ( libc:: EINVAL ) ) ;
1951
+ }
1952
+ }
1953
+
1954
+ let ( dirty_ring_cap, max_bytes, bitmap) = {
1955
+ // Check if KVM_CAP_DIRTY_LOG_RING_ACQ_REL is available, enable if possible
1956
+ let acq_rel_sz = self . check_extension_raw ( KVM_CAP_DIRTY_LOG_RING_ACQ_REL . into ( ) ) ;
1957
+ if acq_rel_sz > 0 {
1958
+ if self . check_extension_raw ( KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP . into ( ) ) != 0 {
1959
+ ( KVM_CAP_DIRTY_LOG_RING_ACQ_REL , acq_rel_sz, true )
1960
+ } else {
1961
+ ( KVM_CAP_DIRTY_LOG_RING_ACQ_REL , acq_rel_sz, false )
1962
+ }
1963
+ } else {
1964
+ let sz = self . check_extension_raw ( KVM_CAP_DIRTY_LOG_RING . into ( ) ) ;
1965
+ if sz > 0 {
1966
+ ( KVM_CAP_DIRTY_LOG_RING , sz, false )
1967
+ } else {
1968
+ ( 0 , 0 , false )
1969
+ }
1970
+ }
1971
+ } ;
1972
+
1973
+ if dirty_ring_cap == 0 {
1974
+ // Neither KVM_CAP_DIRTY_LOG_RING nor KVM_CAP_DIRTY_LOG_RING_ACQ_REL are available
1975
+ return Err ( errno:: Error :: new ( libc:: EOPNOTSUPP ) ) ;
1976
+ }
1977
+
1978
+ let cap_ring_size = bytes. unwrap_or ( max_bytes) ;
1979
+
1980
+ // Check if supplied size is larger than what the kernel supports
1981
+ if cap_ring_size > max_bytes {
1982
+ return Err ( errno:: Error :: new ( libc:: EINVAL ) ) ;
1983
+ }
1984
+
1985
+ // Enable dirty rings with _ACQ_REL if supported, or without otherwise
1986
+ let ar_ring_cap = kvm_enable_cap {
1987
+ cap : dirty_ring_cap,
1988
+ args : [ cap_ring_size as u64 , 0 , 0 , 0 ] ,
1989
+ ..Default :: default ( )
1990
+ } ;
1991
+
1992
+ // Enable the ring cap first
1993
+ self . enable_cap ( & ar_ring_cap) ?;
1994
+
1995
+ if bitmap {
1996
+ let with_bitmap_cap = kvm_enable_cap {
1997
+ cap : KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP ,
1998
+ ..Default :: default ( )
1999
+ } ;
2000
+
2001
+ // Enable backup bitmap
2002
+ self . enable_cap ( & with_bitmap_cap) ?;
2003
+ }
2004
+
2005
+ Ok ( bitmap)
2006
+ }
2007
+
2008
+ /// Resets all vCPU's dirty log rings. This notifies the kernel that pages have been harvested
2009
+ /// from the dirty ring and the corresponding pages can be reprotected.
2010
+ ///
2011
+ /// # Example
2012
+ ///
2013
+ /// ```rust
2014
+ /// # extern crate kvm_ioctls;
2015
+ /// # use kvm_ioctls::{Cap, Kvm};
2016
+ /// let kvm = Kvm::new().unwrap();
2017
+ /// let vm = kvm.create_vm().unwrap();
2018
+ /// vm.enable_dirty_log_ring(None).unwrap();
2019
+ /// if kvm.check_extension(Cap::DirtyLogRing) {
2020
+ /// vm.reset_dirty_rings().unwrap();
2021
+ /// }
2022
+ /// ```
2023
+ ///
2024
+ #[ cfg( target_arch = "x86_64" ) ]
2025
+ pub fn reset_dirty_rings ( & self ) -> Result < c_int > {
2026
+ // SAFETY: Safe because we know that our file is a KVM fd and that the request is one of
2027
+ // the ones defined by kernel.
2028
+ let ret = unsafe { ioctl ( self , KVM_RESET_DIRTY_RINGS ( ) ) } ;
2029
+ if ret < 0 {
2030
+ Err ( errno:: Error :: last ( ) )
2031
+ } else {
2032
+ Ok ( ret)
2033
+ }
2034
+ }
2035
+
1918
2036
/// Sets a specified piece of vm configuration and/or state.
1919
2037
///
1920
2038
/// See the documentation for `KVM_SET_DEVICE_ATTR` in
@@ -2011,7 +2129,11 @@ impl VmFd {
2011
2129
/// `create_vm` from `Kvm`. The function cannot be part of the `VmFd` implementation because
2012
2130
/// then it would be exported with the public `VmFd` interface.
2013
2131
pub fn new_vmfd ( vm : File , run_size : usize ) -> VmFd {
2014
- VmFd { vm, run_size }
2132
+ VmFd {
2133
+ vm,
2134
+ run_size,
2135
+ dirty_ring_bytes : 0 ,
2136
+ }
2015
2137
}
2016
2138
2017
2139
impl AsRawFd for VmFd {
@@ -2601,6 +2723,7 @@ mod tests {
2601
2723
let faulty_vm_fd = VmFd {
2602
2724
vm : unsafe { File :: from_raw_fd ( -2 ) } ,
2603
2725
run_size : 0 ,
2726
+ dirty_ring_bytes : 0 ,
2604
2727
} ;
2605
2728
2606
2729
let invalid_mem_region = kvm_userspace_memory_region {
0 commit comments