aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2019-03-13 19:49:31 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2019-03-28 12:29:09 -0400
commit0f73bbc851ed32d22bbd86be09e0365c460bcd2e (patch)
treeea284f7f136478bbbef72f205ee29944a761a859
parentffac839d040619847217647434b2b02469926871 (diff)
KVM: selftests: complete IO before migrating guest state
Documentation/virtual/kvm/api.txt states: NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO, KVM_EXIT_OSI, KVM_EXIT_PAPR and KVM_EXIT_EPR the corresponding operations are complete (and guest state is consistent) only after userspace has re-entered the kernel with KVM_RUN. The kernel side will first finish incomplete operations and then check for pending signals. Userspace can re-enter the guest with an unmasked signal pending to complete pending operations. Because guest state may be inconsistent, starting state migration after an IO exit without first completing IO may result in test failures, e.g. a proposed change to KVM's handling of %rip in its fast PIO handling[1] will cause the new VM, i.e. the post-migration VM, to have its %rip set to the IN instruction that triggered KVM_EXIT_IO, leading to a test assertion due to a stage mismatch. For simplicitly, require KVM_CAP_IMMEDIATE_EXIT to complete IO and skip the test if it's not available. The addition of KVM_CAP_IMMEDIATE_EXIT predates the state selftest by more than a year. [1] https://patchwork.kernel.org/patch/10848545/ Fixes: fa3899add1056 ("kvm: selftests: add basic test for state save and restore") Reported-by: Jim Mattson <jmattson@google.com> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--tools/testing/selftests/kvm/include/kvm_util.h1
-rw-r--r--tools/testing/selftests/kvm/lib/kvm_util.c16
-rw-r--r--tools/testing/selftests/kvm/x86_64/state_test.c18
3 files changed, 33 insertions, 2 deletions
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index a84785b02557..07b71ad9734a 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -102,6 +102,7 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva);
102struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); 102struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid);
103void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); 103void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid);
104int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); 104int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid);
105void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid);
105void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, 106void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid,
106 struct kvm_mp_state *mp_state); 107 struct kvm_mp_state *mp_state);
107void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); 108void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index b52cfdefecbf..efa0aad8b3c6 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1121,6 +1121,22 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid)
1121 return rc; 1121 return rc;
1122} 1122}
1123 1123
1124void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid)
1125{
1126 struct vcpu *vcpu = vcpu_find(vm, vcpuid);
1127 int ret;
1128
1129 TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
1130
1131 vcpu->state->immediate_exit = 1;
1132 ret = ioctl(vcpu->fd, KVM_RUN, NULL);
1133 vcpu->state->immediate_exit = 0;
1134
1135 TEST_ASSERT(ret == -1 && errno == EINTR,
1136 "KVM_RUN IOCTL didn't exit immediately, rc: %i, errno: %i",
1137 ret, errno);
1138}
1139
1124/* 1140/*
1125 * VM VCPU Set MP State 1141 * VM VCPU Set MP State
1126 * 1142 *
diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c
index 4b3f556265f1..30f75856cf39 100644
--- a/tools/testing/selftests/kvm/x86_64/state_test.c
+++ b/tools/testing/selftests/kvm/x86_64/state_test.c
@@ -134,6 +134,11 @@ int main(int argc, char *argv[])
134 134
135 struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); 135 struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1);
136 136
137 if (!kvm_check_cap(KVM_CAP_IMMEDIATE_EXIT)) {
138 fprintf(stderr, "immediate_exit not available, skipping test\n");
139 exit(KSFT_SKIP);
140 }
141
137 /* Create VM */ 142 /* Create VM */
138 vm = vm_create_default(VCPU_ID, 0, guest_code); 143 vm = vm_create_default(VCPU_ID, 0, guest_code);
139 vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); 144 vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
@@ -156,8 +161,6 @@ int main(int argc, char *argv[])
156 stage, run->exit_reason, 161 stage, run->exit_reason,
157 exit_reason_str(run->exit_reason)); 162 exit_reason_str(run->exit_reason));
158 163
159 memset(&regs1, 0, sizeof(regs1));
160 vcpu_regs_get(vm, VCPU_ID, &regs1);
161 switch (get_ucall(vm, VCPU_ID, &uc)) { 164 switch (get_ucall(vm, VCPU_ID, &uc)) {
162 case UCALL_ABORT: 165 case UCALL_ABORT:
163 TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0], 166 TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0],
@@ -176,6 +179,17 @@ int main(int argc, char *argv[])
176 uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx", 179 uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx",
177 stage, (ulong)uc.args[1]); 180 stage, (ulong)uc.args[1]);
178 181
182 /*
183 * When KVM exits to userspace with KVM_EXIT_IO, KVM guarantees
184 * guest state is consistent only after userspace re-enters the
185 * kernel with KVM_RUN. Complete IO prior to migrating state
186 * to a new VM.
187 */
188 vcpu_run_complete_io(vm, VCPU_ID);
189
190 memset(&regs1, 0, sizeof(regs1));
191 vcpu_regs_get(vm, VCPU_ID, &regs1);
192
179 state = vcpu_save_state(vm, VCPU_ID); 193 state = vcpu_save_state(vm, VCPU_ID);
180 kvm_vm_release(vm); 194 kvm_vm_release(vm);
181 195