@@ -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,112 @@ 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+ 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+
19182040 /// Sets a specified piece of vm configuration and/or state.
19192041 ///
19202042 /// See the documentation for `KVM_SET_DEVICE_ATTR` in
@@ -2011,7 +2133,11 @@ impl VmFd {
20112133/// `create_vm` from `Kvm`. The function cannot be part of the `VmFd` implementation because
20122134/// then it would be exported with the public `VmFd` interface.
20132135pub 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+ }
20152141}
20162142
20172143impl AsRawFd for VmFd {
@@ -2601,6 +2727,7 @@ mod tests {
26012727 let faulty_vm_fd = VmFd {
26022728 vm : unsafe { File :: from_raw_fd ( -2 ) } ,
26032729 run_size : 0 ,
2730+ dirty_ring_bytes : 0 ,
26042731 } ;
26052732
26062733 let invalid_mem_region = kvm_userspace_memory_region {
0 commit comments