Skip to content

Commit 0f73bbc

Browse files
Sean Christophersonbonzini
authored andcommitted
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: fa3899a ("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>
1 parent ffac839 commit 0f73bbc

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

tools/testing/selftests/kvm/include/kvm_util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva);
102102
struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid);
103103
void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid);
104104
int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid);
105+
void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid);
105106
void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid,
106107
struct kvm_mp_state *mp_state);
107108
void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs);

tools/testing/selftests/kvm/lib/kvm_util.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,22 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid)
11211121
return rc;
11221122
}
11231123

1124+
void 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+
11241140
/*
11251141
* VM VCPU Set MP State
11261142
*

tools/testing/selftests/kvm/x86_64/state_test.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ int main(int argc, char *argv[])
134134

135135
struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1);
136136

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+
137142
/* Create VM */
138143
vm = vm_create_default(VCPU_ID, 0, guest_code);
139144
vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
@@ -156,8 +161,6 @@ int main(int argc, char *argv[])
156161
stage, run->exit_reason,
157162
exit_reason_str(run->exit_reason));
158163

159-
memset(&regs1, 0, sizeof(regs1));
160-
vcpu_regs_get(vm, VCPU_ID, &regs1);
161164
switch (get_ucall(vm, VCPU_ID, &uc)) {
162165
case UCALL_ABORT:
163166
TEST_ASSERT(false, "%s at %s:%d", (const char *)uc.args[0],
@@ -176,6 +179,17 @@ int main(int argc, char *argv[])
176179
uc.args[1] == stage, "Unexpected register values vmexit #%lx, got %lx",
177180
stage, (ulong)uc.args[1]);
178181

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+
179193
state = vcpu_save_state(vm, VCPU_ID);
180194
kvm_vm_release(vm);
181195

0 commit comments

Comments
 (0)