@@ -18,7 +18,7 @@ use crate::ioctls::device::DeviceFd;
1818use crate :: ioctls:: device:: new_device;
1919use crate :: ioctls:: vcpu:: VcpuFd ;
2020use crate :: ioctls:: vcpu:: new_vcpu;
21- use crate :: ioctls:: { KvmRunWrapper , Result } ;
21+ use crate :: ioctls:: { KvmDirtyLogRing , KvmRunWrapper , Result } ;
2222use crate :: kvm_ioctls:: * ;
2323use vmm_sys_util:: errno;
2424use vmm_sys_util:: eventfd:: EventFd ;
@@ -59,6 +59,7 @@ impl From<NoDatamatch> for u64 {
5959pub struct VmFd {
6060 vm : File ,
6161 run_size : usize ,
62+ dirty_ring_bytes : usize ,
6263}
6364
6465impl VmFd {
@@ -1214,7 +1215,15 @@ impl VmFd {
12141215
12151216 let kvm_run_ptr = KvmRunWrapper :: mmap_from_fd ( & vcpu, self . run_size ) ?;
12161217
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) )
12181227 }
12191228
12201229 /// Creates a VcpuFd object from a vcpu RawFd.
@@ -1250,7 +1259,14 @@ impl VmFd {
12501259 // SAFETY: we trust the kernel and verified parameters
12511260 let vcpu = unsafe { File :: from_raw_fd ( fd) } ;
12521261 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) )
12541270 }
12551271
12561272 /// Creates an emulated device in the kernel.
@@ -1915,6 +1931,108 @@ impl VmFd {
19151931 Ok ( ( ) )
19161932 }
19171933
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+
19182036 /// Sets a specified piece of vm configuration and/or state.
19192037 ///
19202038 /// See the documentation for `KVM_SET_DEVICE_ATTR` in
@@ -2011,7 +2129,11 @@ impl VmFd {
20112129/// `create_vm` from `Kvm`. The function cannot be part of the `VmFd` implementation because
20122130/// then it would be exported with the public `VmFd` interface.
20132131pub 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+ }
20152137}
20162138
20172139impl AsRawFd for VmFd {
@@ -2601,6 +2723,7 @@ mod tests {
26012723 let faulty_vm_fd = VmFd {
26022724 vm : unsafe { File :: from_raw_fd ( -2 ) } ,
26032725 run_size : 0 ,
2726+ dirty_ring_bytes : 0 ,
26042727 } ;
26052728
26062729 let invalid_mem_region = kvm_userspace_memory_region {
0 commit comments