Skip to content

Commit 3c9fb47

Browse files
Alexandru-Cezar Sardanalxiord
Alexandru-Cezar Sardan
authored andcommitted
snap/restore: extend the number of saved MSRs
KVM can get/set only a maximum of KVM_MAX_MSR_ENTRIES MSRs at a time through ioctl. In some scenarios we need to save more than KVM_MAX_MSR_ENTRIES in the snapshot when the Guest CPU is emulating a lot of MSRs. Change the list of supported MSRs to a HashSet. This allows better flexibility in adding and comparing MSR address lists. Also save a `Vec<Msrs>` instead of a single `Msrs` struct to allow saving an unlimited number of MSRs in the snapshot. Signed-off-by: Alexandru-Cezar Sardan <[email protected]>
1 parent e5498f8 commit 3c9fb47

File tree

2 files changed

+78
-30
lines changed

2 files changed

+78
-30
lines changed

src/vmm/src/version_map.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ lazy_static! {
5353

5454
// v1.2 state change mappings.
5555
version_map.new_version().set_type_version(VmInfo::type_id(), 2);
56+
#[cfg(target_arch = "x86_64")]
57+
version_map.set_type_version(VcpuState::type_id(), 3);
5658

5759
version_map
5860
};

src/vmm/src/vstate/vcpu/x86_64.rs

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Use of this source code is governed by a BSD-style license that can be
66
// found in the THIRD-PARTY file.
77

8+
use std::collections::HashSet;
89
use std::fmt::{Display, Formatter};
910
use std::{fmt, result};
1011

@@ -14,11 +15,11 @@ use arch::x86_64::regs::{SetupFpuError, SetupRegistersError, SetupSpecialRegiste
1415
use cpuid::{c3, filter_cpuid, msrs_to_save_by_cpuid, t2, t2s, VmSpec};
1516
use kvm_bindings::{
1617
kvm_debugregs, kvm_lapic_state, kvm_mp_state, kvm_regs, kvm_sregs, kvm_vcpu_events, kvm_xcrs,
17-
kvm_xsave, CpuId, MsrList, Msrs,
18+
kvm_xsave, CpuId, Msrs, KVM_MAX_MSR_ENTRIES,
1819
};
1920
use kvm_ioctls::{VcpuExit, VcpuFd};
2021
use logger::{error, warn, IncMetric, METRICS};
21-
use versionize::{VersionMap, Versionize, VersionizeResult};
22+
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
2223
use versionize_derive::Versionize;
2324
use vm_memory::{Address, GuestAddress, GuestMemoryMmap};
2425

@@ -216,7 +217,7 @@ pub struct KvmVcpu {
216217
pub pio_bus: Option<devices::Bus>,
217218
pub mmio_bus: Option<devices::Bus>,
218219

219-
msr_list: MsrList,
220+
msr_list: HashSet<u32>,
220221
}
221222

222223
impl KvmVcpu {
@@ -234,7 +235,7 @@ impl KvmVcpu {
234235
fd: kvm_vcpu,
235236
pio_bus: None,
236237
mmio_bus: None,
237-
msr_list: vm.supported_msrs().clone(),
238+
msr_list: vm.supported_msrs().as_slice().iter().copied().collect(),
238239
})
239240
}
240241

@@ -294,11 +295,7 @@ impl KvmVcpu {
294295
// the extra MSRs that we need to save based on a dependency map.
295296
let extra_msrs =
296297
msrs_to_save_by_cpuid(&cpuid).map_err(KvmVcpuConfigureError::FilterCpuid)?;
297-
for msr in extra_msrs {
298-
self.msr_list
299-
.push(msr)
300-
.map_err(KvmVcpuConfigureError::PushMsrEntries)?;
301-
}
298+
self.msr_list.extend(extra_msrs);
302299

303300
// TODO: Some MSRs depend on values of other MSRs. This dependency will need to
304301
// be implemented. For now we define known dependencies statically in the CPU
@@ -310,11 +307,7 @@ impl KvmVcpu {
310307
// to save at snapshot as well.
311308
// C3 and T2 currently don't have extra MSRs to save/set
312309
if vcpu_config.cpu_template == CpuFeaturesTemplate::T2S {
313-
for msr in t2s::msr_entries_to_save() {
314-
self.msr_list
315-
.push(*msr)
316-
.map_err(KvmVcpuConfigureError::PushMsrEntries)?;
317-
}
310+
self.msr_list.extend(t2s::msr_entries_to_save());
318311
t2s::update_msr_entries(&mut msr_boot_entries);
319312
}
320313
// By this point we know that at snapshot, the list of MSRs we need to
@@ -367,17 +360,24 @@ impl KvmVcpu {
367360
// GET_MSRS requires a pre-populated data structure to do something
368361
// meaningful. For SET_MSRS it will then contain good data.
369362

370-
// Build the list of MSRs we want to save.
371-
let num_msrs = self.msr_list.as_fam_struct_ref().nmsrs as usize;
372-
let mut msrs = Msrs::new(num_msrs).map_err(Error::Fam)?;
373-
{
374-
let indices = self.msr_list.as_slice();
363+
// Build the list of MSRs we want to save. Sometimes we need to save
364+
// more than KVM_MAX_MSR_ENTRIES in the snapshot, so we use a Vec<Msrs>
365+
// to allow an unlimited number.
366+
let mut all_msrs: Vec<Msrs> = Vec::new();
367+
let msr_list: Vec<&u32> = self.msr_list.iter().collect();
368+
369+
// KVM only supports getting KVM_MAX_MSR_ENTRIES at a time so chunk
370+
// them up into `Msrs` so it's easy to pass to the ioctl.
371+
for chunk in msr_list.chunks(KVM_MAX_MSR_ENTRIES) {
372+
let mut msrs = Msrs::new(chunk.len()).map_err(Error::Fam)?;
375373
let msr_entries = msrs.as_mut_slice();
376-
assert_eq!(indices.len(), msr_entries.len());
377-
for (pos, index) in indices.iter().enumerate() {
378-
msr_entries[pos].index = *index;
374+
assert_eq!(chunk.len(), msr_entries.len());
375+
for (pos, index) in chunk.iter().enumerate() {
376+
msr_entries[pos].index = **index;
379377
}
378+
all_msrs.push(msrs);
380379
}
380+
381381
let mp_state = self.fd.get_mp_state().map_err(Error::VcpuGetMpState)?;
382382
let regs = self.fd.get_regs().map_err(Error::VcpuGetRegs)?;
383383
let sregs = self.fd.get_sregs().map_err(Error::VcpuGetSregs)?;
@@ -392,9 +392,12 @@ impl KvmVcpu {
392392
warn!("TSC freq not available. Snapshot cannot be loaded on a different CPU model.");
393393
None
394394
});
395-
let nmsrs = self.fd.get_msrs(&mut msrs).map_err(Error::VcpuGetMsrs)?;
396-
if nmsrs != num_msrs {
397-
return Err(Error::VcpuGetMSRSIncomplete);
395+
for msrs in all_msrs.iter_mut() {
396+
let expected_nmsrs = msrs.as_slice().len();
397+
let nmsrs = self.fd.get_msrs(msrs).map_err(Error::VcpuGetMsrs)?;
398+
if nmsrs != expected_nmsrs {
399+
return Err(Error::VcpuGetMSRSIncomplete);
400+
}
398401
}
399402
let vcpu_events = self
400403
.fd
@@ -406,7 +409,8 @@ impl KvmVcpu {
406409
.fd
407410
.get_cpuid2(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
408411
.map_err(Error::VcpuGetCpuid)?,
409-
msrs,
412+
saved_msrs: all_msrs,
413+
msrs: Msrs::new(0).map_err(Error::Fam)?,
410414
debug_regs,
411415
lapic,
412416
mp_state,
@@ -486,10 +490,11 @@ impl KvmVcpu {
486490
self.fd
487491
.set_lapic(&state.lapic)
488492
.map_err(Error::VcpuSetLapic)?;
489-
let nmsrs = self.fd.set_msrs(&state.msrs).map_err(Error::VcpuSetMsrs)?;
490-
let num_msrs = state.msrs.as_fam_struct_ref().nmsrs as usize;
491-
if nmsrs < num_msrs {
492-
return Err(Error::VcpuSetMSRSIncomplete);
493+
for msrs in &state.saved_msrs {
494+
let nmsrs = self.fd.set_msrs(msrs).map_err(Error::VcpuSetMsrs)?;
495+
if nmsrs < msrs.as_fam_struct_ref().nmsrs as usize {
496+
return Err(Error::VcpuSetMSRSIncomplete);
497+
}
493498
}
494499
self.fd
495500
.set_vcpu_events(&state.vcpu_events)
@@ -535,7 +540,10 @@ impl KvmVcpu {
535540
// NOTICE: Any changes to this structure require a snapshot version bump.
536541
pub struct VcpuState {
537542
pub cpuid: CpuId,
543+
#[version(end = 3, default_fn = "default_msrs")]
538544
msrs: Msrs,
545+
#[version(start = 3, de_fn = "de_saved_msrs", ser_fn = "ser_saved_msrs")]
546+
saved_msrs: Vec<Msrs>,
539547
debug_regs: kvm_debugregs,
540548
lapic: kvm_lapic_state,
541549
mp_state: kvm_mp_state,
@@ -565,6 +573,43 @@ impl VcpuState {
565573

566574
Ok(())
567575
}
576+
577+
fn default_msrs(_source_version: u16) -> Msrs {
578+
// Safe to unwrap since Msrs::new() only returns an error if the number
579+
// of elements exceeds KVM_MAX_MSR_ENTRIES
580+
Msrs::new(0).unwrap()
581+
}
582+
583+
fn de_saved_msrs(&mut self, source_version: u16) -> VersionizeResult<()> {
584+
if source_version < 3 {
585+
self.saved_msrs.push(self.msrs.clone());
586+
}
587+
Ok(())
588+
}
589+
590+
fn ser_saved_msrs(&mut self, target_version: u16) -> VersionizeResult<()> {
591+
match self.saved_msrs.len() {
592+
0 => Err(VersionizeError::Serialize(
593+
"Cannot serialize MSRs because the MSR list is empty".to_string(),
594+
)),
595+
1 => {
596+
if target_version < 3 {
597+
self.msrs = self.saved_msrs[0].clone();
598+
Ok(())
599+
} else {
600+
Err(VersionizeError::Serialize(format!(
601+
"Cannot serialize MSRs to target version {}",
602+
target_version
603+
)))
604+
}
605+
}
606+
_ => Err(VersionizeError::Serialize(
607+
"Cannot serialize MSRs. The uVM state needs to save
608+
more MSRs than the target snapshot version supports."
609+
.to_string(),
610+
)),
611+
}
612+
}
568613
}
569614

570615
#[cfg(test)]
@@ -585,6 +630,7 @@ mod tests {
585630
VcpuState {
586631
cpuid: CpuId::new(1).unwrap(),
587632
msrs: Msrs::new(1).unwrap(),
633+
saved_msrs: vec![Msrs::new(1).unwrap()],
588634
debug_regs: Default::default(),
589635
lapic: Default::default(),
590636
mp_state: Default::default(),

0 commit comments

Comments
 (0)