Skip to content

Commit dbf8b68

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 <yegorlz@amazon.co.uk>
1 parent 7635cac commit dbf8b68

File tree

11 files changed

+366
-254
lines changed

11 files changed

+366
-254
lines changed

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::{VmConfig, VmConfigError};
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,
@@ -473,7 +481,7 @@ pub fn build_microvm_from_snapshot(
473481
uffd,
474482
vm_resources.vm_config.track_dirty_pages,
475483
vm_resources.vm_config.vcpu_count,
476-
microvm_state.vm_state.kvm_cap_modifiers.clone(),
484+
microvm_state.kvm_state.kvm_cap_modifiers.clone(),
477485
)?;
478486

479487
#[cfg(target_arch = "x86_64")]
@@ -735,11 +743,16 @@ fn attach_legacy_devices_aarch64(
735743
.map_err(VmmError::RegisterMMIODevice)
736744
}
737745

738-
fn create_vcpus(vm: &Vm, vcpu_count: u8, exit_evt: &EventFd) -> Result<Vec<Vcpu>, VmmError> {
746+
fn create_vcpus(
747+
kvm: &Kvm,
748+
vm: &Vm,
749+
vcpu_count: u8,
750+
exit_evt: &EventFd,
751+
) -> Result<Vec<Vcpu>, VmmError> {
739752
let mut vcpus = Vec::with_capacity(vcpu_count as usize);
740753
for cpu_idx in 0..vcpu_count {
741754
let exit_evt = exit_evt.try_clone().map_err(VmmError::EventFd)?;
742-
let vcpu = Vcpu::new(cpu_idx, vm, exit_evt).map_err(VmmError::VcpuCreate)?;
755+
let vcpu = Vcpu::new(cpu_idx, vm, kvm, exit_evt).map_err(VmmError::VcpuCreate)?;
743756
vcpus.push(vcpu);
744757
}
745758
Ok(vcpus)
@@ -762,7 +775,7 @@ pub fn configure_system_for_boot(
762775
#[cfg(target_arch = "x86_64")]
763776
let cpu_config = {
764777
use crate::cpu_config::x86_64::cpuid;
765-
let cpuid = cpuid::Cpuid::try_from(vmm.vm.supported_cpuid().clone())
778+
let cpuid = cpuid::Cpuid::try_from(vmm.kvm.supported_cpuid.clone())
766779
.map_err(GuestConfigError::CpuidFromKvmCpuid)?;
767780
let msrs = vcpus[0]
768781
.kvm_vcpu
@@ -1108,7 +1121,8 @@ pub(crate) mod tests {
11081121
.map_err(StartMicrovmError::Internal)
11091122
.unwrap();
11101123

1111-
let mut vm = Vm::new(vec![]).unwrap();
1124+
let kvm = Kvm::new(vec![]).unwrap();
1125+
let mut vm = Vm::new(&kvm).unwrap();
11121126
vm.memory_init(&guest_memory, false).unwrap();
11131127
let mmio_device_manager = MMIODeviceManager::new();
11141128
let acpi_device_manager = ACPIDeviceManager::new();
@@ -1134,14 +1148,15 @@ pub(crate) mod tests {
11341148
#[cfg(target_arch = "aarch64")]
11351149
{
11361150
let exit_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap();
1137-
let _vcpu = Vcpu::new(1, &vm, exit_evt).unwrap();
1151+
let _vcpu = Vcpu::new(1, &vm, &kvm, exit_evt).unwrap();
11381152
setup_interrupt_controller(&mut vm, 1).unwrap();
11391153
}
11401154

11411155
Vmm {
11421156
events_observer: Some(std::io::stdin()),
11431157
instance_info: InstanceInfo::default(),
11441158
shutdown_exit_code: None,
1159+
kvm,
11451160
vm,
11461161
guest_memory,
11471162
uffd: None,
@@ -1359,15 +1374,16 @@ pub(crate) mod tests {
13591374
let vcpu_count = 2;
13601375
let guest_memory = arch_mem(128 << 20);
13611376

1377+
let kvm = Kvm::new(vec![]).expect("Cannot create Kvm");
13621378
#[allow(unused_mut)]
1363-
let mut vm = Vm::new(vec![]).unwrap();
1379+
let mut vm = Vm::new(&kvm).unwrap();
13641380
vm.memory_init(&guest_memory, false).unwrap();
13651381
let evfd = EventFd::new(libc::EFD_NONBLOCK).unwrap();
13661382

13671383
#[cfg(target_arch = "x86_64")]
13681384
setup_interrupt_controller(&mut vm).unwrap();
13691385

1370-
let vcpu_vec = create_vcpus(&vm, vcpu_count, &evfd).unwrap();
1386+
let vcpu_vec = create_vcpus(&kvm, &vm, vcpu_count, &evfd).unwrap();
13711387
assert_eq!(vcpu_vec.len(), vcpu_count as usize);
13721388
}
13731389

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, MachineConfigUpdate, VmC
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)