Skip to content

Commit 6f3b4c9

Browse files
committed
refactor: move KVM related logic into a separate struct
Vm constructor was the only place where the `/dev/kvm` was open and only there we could do any KVM (not VM) specific checks. By moving this KVM logic into separate struct we can can do KVM specific actions (like checking optional KVM capabilities) without needing to reopen `/dev/kvm` again or storing it in `Vm` where it does not belong. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 3fb06e9 commit 6f3b4c9

File tree

12 files changed

+372
-273
lines changed

12 files changed

+372
-273
lines changed

src/vmm/src/arch/aarch64/vcpu.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,16 @@ pub fn set_mpstate(vcpufd: &VcpuFd, state: kvm_mp_state) -> Result<(), VcpuError
214214
#[cfg(test)]
215215
mod tests {
216216
#![allow(clippy::undocumented_unsafe_blocks)]
217-
use kvm_ioctls::Kvm;
218217

219218
use super::*;
220219
use crate::arch::aarch64::layout;
221220
use crate::test_utils::arch_mem;
221+
use crate::vstate::kvm::Kvm;
222222

223223
#[test]
224224
fn test_setup_regs() {
225-
let kvm = Kvm::new().unwrap();
226-
let vm = kvm.create_vm().unwrap();
225+
let kvm = Kvm::new(vec![]).unwrap();
226+
let vm = kvm.fd.create_vm().unwrap();
227227
let vcpu = vm.create_vcpu(0).unwrap();
228228
let mem = arch_mem(layout::FDT_MAX_SIZE + 0x1000);
229229

@@ -242,8 +242,8 @@ mod tests {
242242

243243
#[test]
244244
fn test_read_mpidr() {
245-
let kvm = Kvm::new().unwrap();
246-
let vm = kvm.create_vm().unwrap();
245+
let kvm = Kvm::new(vec![]).unwrap();
246+
let vm = kvm.fd.create_vm().unwrap();
247247
let vcpu = vm.create_vcpu(0).unwrap();
248248
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
249249
vm.get_preferred_target(&mut kvi).unwrap();
@@ -261,8 +261,8 @@ mod tests {
261261

262262
#[test]
263263
fn test_get_set_regs() {
264-
let kvm = Kvm::new().unwrap();
265-
let vm = kvm.create_vm().unwrap();
264+
let kvm = Kvm::new(vec![]).unwrap();
265+
let vm = kvm.fd.create_vm().unwrap();
266266
let vcpu = vm.create_vcpu(0).unwrap();
267267
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
268268
vm.get_preferred_target(&mut kvi).unwrap();
@@ -283,8 +283,8 @@ mod tests {
283283
fn test_mpstate() {
284284
use std::os::unix::io::AsRawFd;
285285

286-
let kvm = Kvm::new().unwrap();
287-
let vm = kvm.create_vm().unwrap();
286+
let kvm = Kvm::new(vec![]).unwrap();
287+
let vm = kvm.fd.create_vm().unwrap();
288288
let vcpu = vm.create_vcpu(0).unwrap();
289289
let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
290290
vm.get_preferred_target(&mut kvi).unwrap();

src/vmm/src/builder.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ use crate::utils::u64_to_usize;
6868
use crate::vmm_config::boot_source::BootConfig;
6969
use crate::vmm_config::instance_info::InstanceInfo;
7070
use crate::vmm_config::machine_config::{MachineConfig, MachineConfigError};
71+
use crate::vstate::kvm::Kvm;
7172
use crate::vstate::memory::{GuestAddress, GuestMemory, GuestMemoryMmap};
7273
use crate::vstate::vcpu::{Vcpu, VcpuConfig, VcpuError};
7374
use crate::vstate::vm::Vm;
@@ -160,11 +161,17 @@ fn create_vmm_and_vcpus(
160161
) -> Result<(Vmm, Vec<Vcpu>), StartMicrovmError> {
161162
use self::StartMicrovmError::*;
162163

164+
let kvm = Kvm::new(kvm_capabilities)
165+
.map_err(VmmError::Kvm)
166+
.map_err(StartMicrovmError::Internal)?;
163167
// Set up Kvm Vm and register memory regions.
164168
// Build custom CPU config if a custom template is provided.
165-
let mut vm = Vm::new(kvm_capabilities)
169+
let mut vm = Vm::new(&kvm)
166170
.map_err(VmmError::Vm)
167171
.map_err(StartMicrovmError::Internal)?;
172+
kvm.check_memory(&guest_memory)
173+
.map_err(VmmError::Kvm)
174+
.map_err(StartMicrovmError::Internal)?;
168175
vm.memory_init(&guest_memory, track_dirty_pages)
169176
.map_err(VmmError::Vm)
170177
.map_err(StartMicrovmError::Internal)?;
@@ -186,7 +193,7 @@ fn create_vmm_and_vcpus(
186193
#[cfg(target_arch = "x86_64")]
187194
let (vcpus, pio_device_manager) = {
188195
setup_interrupt_controller(&mut vm)?;
189-
let vcpus = create_vcpus(&vm, vcpu_count, &vcpus_exit_evt).map_err(Internal)?;
196+
let vcpus = create_vcpus(&kvm, &vm, vcpu_count, &vcpus_exit_evt).map_err(Internal)?;
190197

191198
// Make stdout non blocking.
192199
set_stdout_nonblocking();
@@ -218,7 +225,7 @@ fn create_vmm_and_vcpus(
218225
// Search for `kvm_arch_vcpu_create` in arch/arm/kvm/arm.c.
219226
#[cfg(target_arch = "aarch64")]
220227
let vcpus = {
221-
let vcpus = create_vcpus(&vm, vcpu_count, &vcpus_exit_evt).map_err(Internal)?;
228+
let vcpus = create_vcpus(&kvm, &vm, vcpu_count, &vcpus_exit_evt).map_err(Internal)?;
222229
setup_interrupt_controller(&mut vm, vcpu_count)?;
223230
vcpus
224231
};
@@ -227,6 +234,7 @@ fn create_vmm_and_vcpus(
227234
events_observer: Some(std::io::stdin()),
228235
instance_info: instance_info.clone(),
229236
shutdown_exit_code: None,
237+
kvm,
230238
vm,
231239
guest_memory,
232240
uffd,
@@ -476,7 +484,7 @@ pub fn build_microvm_from_snapshot(
476484
uffd,
477485
vm_resources.machine_config.track_dirty_pages,
478486
vm_resources.machine_config.vcpu_count,
479-
microvm_state.vm_state.kvm_cap_modifiers.clone(),
487+
microvm_state.kvm_state.kvm_cap_modifiers.clone(),
480488
)?;
481489

482490
#[cfg(target_arch = "x86_64")]
@@ -738,11 +746,16 @@ fn attach_legacy_devices_aarch64(
738746
.map_err(VmmError::RegisterMMIODevice)
739747
}
740748

741-
fn create_vcpus(vm: &Vm, vcpu_count: u8, exit_evt: &EventFd) -> Result<Vec<Vcpu>, VmmError> {
749+
fn create_vcpus(
750+
kvm: &Kvm,
751+
vm: &Vm,
752+
vcpu_count: u8,
753+
exit_evt: &EventFd,
754+
) -> Result<Vec<Vcpu>, VmmError> {
742755
let mut vcpus = Vec::with_capacity(vcpu_count as usize);
743756
for cpu_idx in 0..vcpu_count {
744757
let exit_evt = exit_evt.try_clone().map_err(VmmError::EventFd)?;
745-
let vcpu = Vcpu::new(cpu_idx, vm, exit_evt).map_err(VmmError::VcpuCreate)?;
758+
let vcpu = Vcpu::new(cpu_idx, vm, kvm, exit_evt).map_err(VmmError::VcpuCreate)?;
746759
vcpus.push(vcpu);
747760
}
748761
Ok(vcpus)
@@ -765,7 +778,7 @@ pub fn configure_system_for_boot(
765778
#[cfg(target_arch = "x86_64")]
766779
let cpu_config = {
767780
use crate::cpu_config::x86_64::cpuid;
768-
let cpuid = cpuid::Cpuid::try_from(vmm.vm.supported_cpuid().clone())
781+
let cpuid = cpuid::Cpuid::try_from(vmm.kvm.supported_cpuid.clone())
769782
.map_err(GuestConfigError::CpuidFromKvmCpuid)?;
770783
let msrs = vcpus[0]
771784
.kvm_vcpu
@@ -1111,7 +1124,8 @@ pub(crate) mod tests {
11111124
.map_err(StartMicrovmError::Internal)
11121125
.unwrap();
11131126

1114-
let mut vm = Vm::new(vec![]).unwrap();
1127+
let kvm = Kvm::new(vec![]).unwrap();
1128+
let mut vm = Vm::new(&kvm).unwrap();
11151129
vm.memory_init(&guest_memory, false).unwrap();
11161130
let mmio_device_manager = MMIODeviceManager::new();
11171131
let acpi_device_manager = ACPIDeviceManager::new();
@@ -1137,14 +1151,15 @@ pub(crate) mod tests {
11371151
#[cfg(target_arch = "aarch64")]
11381152
{
11391153
let exit_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
1140-
let _vcpu = Vcpu::new(1, &vm, exit_evt).unwrap();
1154+
let _vcpu = Vcpu::new(1, &vm, &kvm, exit_evt).unwrap();
11411155
setup_interrupt_controller(&mut vm, 1).unwrap();
11421156
}
11431157

11441158
Vmm {
11451159
events_observer: Some(std::io::stdin()),
11461160
instance_info: InstanceInfo::default(),
11471161
shutdown_exit_code: None,
1162+
kvm,
11481163
vm,
11491164
guest_memory,
11501165
uffd: None,
@@ -1362,15 +1377,16 @@ pub(crate) mod tests {
13621377
let vcpu_count = 2;
13631378
let guest_memory = arch_mem(128 << 20);
13641379

1380+
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
13651381
#[allow(unused_mut)]
1366-
let mut vm = Vm::new(vec![]).unwrap();
1382+
let mut vm = Vm::new(&kvm).unwrap();
13671383
vm.memory_init(&guest_memory, false).unwrap();
13681384
let evfd = EventFd::new(libc::EFD_NONBLOCK).unwrap();
13691385

13701386
#[cfg(target_arch = "x86_64")]
13711387
setup_interrupt_controller(&mut vm).unwrap();
13721388

1373-
let vcpu_vec = create_vcpus(&vm, vcpu_count, &evfd).unwrap();
1389+
let vcpu_vec = create_vcpus(&kvm, &vm, vcpu_count, &evfd).unwrap();
13741390
assert_eq!(vcpu_vec.len(), vcpu_count as usize);
13751391
}
13761392

src/vmm/src/device_manager/legacy.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,11 @@ impl PortIODeviceManager {
244244
#[cfg(test)]
245245
mod tests {
246246
use super::*;
247-
use crate::test_utils::single_region_mem;
248-
use crate::Vm;
247+
use crate::vstate::vm::tests::setup_vm_with_memory;
249248

250249
#[test]
251250
fn test_register_legacy_devices() {
252-
let guest_mem = single_region_mem(0x1000);
253-
let mut vm = Vm::new(vec![]).unwrap();
254-
vm.memory_init(&guest_mem, false).unwrap();
251+
let (_, mut vm, _) = setup_vm_with_memory(0x1000);
255252
crate::builder::setup_interrupt_controller(&mut vm).unwrap();
256253
let mut ldm = PortIODeviceManager::new(
257254
Arc::new(Mutex::new(BusDevice::Serial(SerialDevice {

src/vmm/src/device_manager/mmio.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ mod tests {
544544
use crate::devices::virtio::queue::Queue;
545545
use crate::devices::virtio::ActivateError;
546546
use crate::test_utils::multi_region_mem;
547+
use crate::vstate::kvm::Kvm;
547548
use crate::vstate::memory::{GuestAddress, GuestMemoryMmap};
548549
use crate::{builder, Vm};
549550

@@ -661,7 +662,8 @@ mod tests {
661662
let start_addr1 = GuestAddress(0x0);
662663
let start_addr2 = GuestAddress(0x1000);
663664
let guest_mem = multi_region_mem(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]);
664-
let mut vm = Vm::new(vec![]).unwrap();
665+
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
666+
let mut vm = Vm::new(&kvm).unwrap();
665667
vm.memory_init(&guest_mem, false).unwrap();
666668
let mut device_manager = MMIODeviceManager::new();
667669
let mut resource_allocator = ResourceAllocator::new().unwrap();
@@ -690,7 +692,8 @@ mod tests {
690692
let start_addr1 = GuestAddress(0x0);
691693
let start_addr2 = GuestAddress(0x1000);
692694
let guest_mem = multi_region_mem(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]);
693-
let mut vm = Vm::new(vec![]).unwrap();
695+
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
696+
let mut vm = Vm::new(&kvm).unwrap();
694697
vm.memory_init(&guest_mem, false).unwrap();
695698
let mut device_manager = MMIODeviceManager::new();
696699
let mut resource_allocator = ResourceAllocator::new().unwrap();
@@ -744,7 +747,8 @@ mod tests {
744747
let start_addr1 = GuestAddress(0x0);
745748
let start_addr2 = GuestAddress(0x1000);
746749
let guest_mem = multi_region_mem(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]);
747-
let mut vm = Vm::new(vec![]).unwrap();
750+
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
751+
let mut vm = Vm::new(&kvm).unwrap();
748752
vm.memory_init(&guest_mem, false).unwrap();
749753

750754
let mem_clone = guest_mem.clone();

src/vmm/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ use userfaultfd::Uffd;
127127
use vmm_sys_util::epoll::EventSet;
128128
use vmm_sys_util::eventfd::EventFd;
129129
use vmm_sys_util::terminal::Terminal;
130+
use vstate::kvm::Kvm;
130131
use vstate::vcpu::{self, KvmVcpuConfigureError, StartThreadedError, VcpuSendEventError};
131132

132133
use crate::arch::DeviceType;
@@ -255,6 +256,8 @@ pub enum VmmError {
255256
VcpuSpawn(io::Error),
256257
/// Vm error: {0}
257258
Vm(vstate::vm::VmError),
259+
/// Kvm error: {0}
260+
Kvm(vstate::kvm::KvmError),
258261
/// Error thrown by observer object on Vmm initialization: {0}
259262
VmmObserverInit(vmm_sys_util::errno::Error),
260263
/// Error thrown by observer object on Vmm teardown: {0}
@@ -307,6 +310,7 @@ pub struct Vmm {
307310
shutdown_exit_code: Option<FcExitCode>,
308311

309312
// Guest VM core resources.
313+
kvm: Kvm,
310314
vm: Vm,
311315
guest_memory: GuestMemoryMmap,
312316
// Save UFFD in order to keep it open in the Firecracker process, as well.
@@ -511,6 +515,7 @@ impl Vmm {
511515
pub fn save_state(&mut self, vm_info: &VmInfo) -> Result<MicrovmState, MicrovmStateError> {
512516
use self::MicrovmStateError::SaveVmState;
513517
let vcpu_states = self.save_vcpu_states()?;
518+
let kvm_state = self.kvm.save_state();
514519
let vm_state = {
515520
#[cfg(target_arch = "x86_64")]
516521
{
@@ -531,6 +536,7 @@ impl Vmm {
531536
Ok(MicrovmState {
532537
vm_info: vm_info.clone(),
533538
memory_state,
539+
kvm_state,
534540
vm_state,
535541
vcpu_states,
536542
device_states,

src/vmm/src/persist.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use crate::vmm_config::machine_config::{HugePageConfig, MachineConfigError, Mach
3636
use crate::vmm_config::snapshot::{
3737
CreateSnapshotParams, LoadSnapshotParams, MemBackendType, SnapshotType,
3838
};
39+
use crate::vstate::kvm::KvmState;
3940
use crate::vstate::memory::{
4041
GuestMemory, GuestMemoryExtension, GuestMemoryMmap, GuestMemoryState, MemoryError,
4142
};
@@ -77,6 +78,8 @@ pub struct MicrovmState {
7778
pub vm_info: VmInfo,
7879
/// Memory state.
7980
pub memory_state: GuestMemoryState,
81+
/// KVM KVM state.
82+
pub kvm_state: KvmState,
8083
/// VM KVM state.
8184
pub vm_state: VmState,
8285
/// Vcpu states.
@@ -736,6 +739,7 @@ mod tests {
736739
device_states: states,
737740
memory_state,
738741
vcpu_states,
742+
kvm_state: Default::default(),
739743
vm_info: VmInfo {
740744
mem_size_mib: 1u64,
741745
..Default::default()

0 commit comments

Comments
 (0)