Skip to content

Commit 0efae50

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 a separate struct we can can do KVM specific actions (like checking optional KVM capabilities) without needing to reopen the `/dev/kvm` again. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 3fb06e9 commit 0efae50

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)