|
5 | 5 | // Use of this source code is governed by a BSD-style license that can be
|
6 | 6 | // found in the THIRD-PARTY file.
|
7 | 7 |
|
8 |
| -use std::collections::{HashMap, HashSet}; |
| 8 | +use std::collections::BTreeMap; |
9 | 9 | use std::fmt::Debug;
|
10 | 10 |
|
11 | 11 | use kvm_bindings::{
|
@@ -143,7 +143,9 @@ pub struct KvmVcpu {
|
143 | 143 | pub fd: VcpuFd,
|
144 | 144 | /// Vcpu peripherals, such as buses
|
145 | 145 | pub(super) peripherals: Peripherals,
|
146 |
| - msrs_to_save: HashSet<u32>, |
| 146 | + /// The list of MSRs to include in a VM snapshot, in the same order as KVM returned them |
| 147 | + /// from KVM_GET_MSR_INDEX_LIST |
| 148 | + msrs_to_save: Vec<u32>, |
147 | 149 | }
|
148 | 150 |
|
149 | 151 | /// Vcpu peripherals
|
@@ -172,7 +174,7 @@ impl KvmVcpu {
|
172 | 174 | index,
|
173 | 175 | fd: kvm_vcpu,
|
174 | 176 | peripherals: Default::default(),
|
175 |
| - msrs_to_save: vm.msrs_to_save().as_slice().iter().copied().collect(), |
| 177 | + msrs_to_save: vm.msrs_to_save().as_slice().to_vec(), |
176 | 178 | })
|
177 | 179 | }
|
178 | 180 |
|
@@ -416,8 +418,8 @@ impl KvmVcpu {
|
416 | 418 | /// # Errors
|
417 | 419 | ///
|
418 | 420 | /// * When `KvmVcpu::get_msr_chunks()` returns errors.
|
419 |
| - pub fn get_msrs(&self, msr_index_list: &[u32]) -> Result<HashMap<u32, u64>, KvmVcpuError> { |
420 |
| - let mut msrs: HashMap<u32, u64> = HashMap::new(); |
| 421 | + pub fn get_msrs(&self, msr_index_list: &[u32]) -> Result<BTreeMap<u32, u64>, KvmVcpuError> { |
| 422 | + let mut msrs = BTreeMap::new(); |
421 | 423 | self.get_msr_chunks(msr_index_list)?
|
422 | 424 | .iter()
|
423 | 425 | .for_each(|msr_chunk| {
|
@@ -469,8 +471,7 @@ impl KvmVcpu {
|
469 | 471 | None
|
470 | 472 | });
|
471 | 473 | let cpuid = self.get_cpuid()?;
|
472 |
| - let saved_msrs = |
473 |
| - self.get_msr_chunks(&self.msrs_to_save.iter().copied().collect::<Vec<_>>())?; |
| 474 | + let saved_msrs = self.get_msr_chunks(&self.msrs_to_save.to_vec())?; |
474 | 475 | let vcpu_events = self
|
475 | 476 | .fd
|
476 | 477 | .get_vcpu_events()
|
@@ -678,7 +679,7 @@ mod tests {
|
678 | 679 | use std::os::unix::io::AsRawFd;
|
679 | 680 |
|
680 | 681 | use kvm_bindings::kvm_msr_entry;
|
681 |
| - use kvm_ioctls::Cap; |
| 682 | + use kvm_ioctls::{Cap, Kvm}; |
682 | 683 |
|
683 | 684 | use super::*;
|
684 | 685 | use crate::arch::x86_64::cpu_model::CpuModel;
|
@@ -863,7 +864,7 @@ mod tests {
|
863 | 864 | smt: false,
|
864 | 865 | cpu_config: CpuConfiguration {
|
865 | 866 | cpuid: Cpuid::try_from(vm.supported_cpuid().clone()).unwrap(),
|
866 |
| - msrs: HashMap::new(), |
| 867 | + msrs: BTreeMap::new(), |
867 | 868 | },
|
868 | 869 | };
|
869 | 870 | vcpu.configure(&vm_mem, GuestAddress(0), &vcpu_config)
|
@@ -925,7 +926,7 @@ mod tests {
|
925 | 926 | smt: false,
|
926 | 927 | cpu_config: CpuConfiguration {
|
927 | 928 | cpuid: Cpuid::try_from(vm.supported_cpuid().clone()).unwrap(),
|
928 |
| - msrs: HashMap::new(), |
| 929 | + msrs: BTreeMap::new(), |
929 | 930 | },
|
930 | 931 | };
|
931 | 932 | vcpu.configure(&vm_mem, GuestAddress(0), &vcpu_config)
|
@@ -1003,8 +1004,7 @@ mod tests {
|
1003 | 1004 | // Test `get_msrs()` with the MSR indices that should be serialized into snapshots.
|
1004 | 1005 | // The MSR indices should be valid and this test should succeed.
|
1005 | 1006 | let (_, vcpu, _) = setup_vcpu(0x1000);
|
1006 |
| - vcpu.get_msrs(&vcpu.msrs_to_save.iter().copied().collect::<Vec<_>>()) |
1007 |
| - .unwrap(); |
| 1007 | + vcpu.get_msrs(&vcpu.msrs_to_save.to_vec()).unwrap(); |
1008 | 1008 | }
|
1009 | 1009 |
|
1010 | 1010 | #[test]
|
@@ -1125,4 +1125,32 @@ mod tests {
|
1125 | 1125 | &[(MSR_IA32_TSC_DEADLINE, 1), (MSR_IA32_TSC, 2)],
|
1126 | 1126 | );
|
1127 | 1127 | }
|
| 1128 | + |
| 1129 | + #[test] |
| 1130 | + fn test_get_msr_chunks_preserved_order() { |
| 1131 | + // Regression test for #4666 |
| 1132 | + |
| 1133 | + let kvm = Kvm::new().unwrap(); |
| 1134 | + let vm = Vm::new(Vec::new()).unwrap(); |
| 1135 | + let vcpu = KvmVcpu::new(0, &vm).unwrap(); |
| 1136 | + |
| 1137 | + // The list of supported MSR indices, in the order they were returned by KVM |
| 1138 | + let msrs_to_save = crate::arch::x86_64::msr::get_msrs_to_save(&kvm).unwrap(); |
| 1139 | + // The MSRs after processing. The order should be identical to the one returned by KVM, with |
| 1140 | + // the exception of deferred MSRs, which should be moved to the end (but show up in the same |
| 1141 | + // order as they are listed in [`DEFERRED_MSRS`]. |
| 1142 | + let msr_chunks = vcpu.get_msr_chunks(&vcpu.msrs_to_save).unwrap(); |
| 1143 | + |
| 1144 | + msr_chunks |
| 1145 | + .iter() |
| 1146 | + .flat_map(|chunk| chunk.as_slice().iter()) |
| 1147 | + .zip( |
| 1148 | + msrs_to_save |
| 1149 | + .as_slice() |
| 1150 | + .iter() |
| 1151 | + .filter(|&idx| !DEFERRED_MSRS.contains(idx)) |
| 1152 | + .chain(DEFERRED_MSRS.iter()), |
| 1153 | + ) |
| 1154 | + .for_each(|(left, &right)| assert_eq!(left.index, right)); |
| 1155 | + } |
1128 | 1156 | }
|
0 commit comments