mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-13 07:54:09 -04:00
KVM: selftests: Trigger save+restore randomly in the #PF stress test
Instead of an explicit GUEST_SYNC() after each access+#PF, run another thread that keeps sending SIGUSR to the vCPU thread, essentially triggering exits to userspace and save+restore on random points in guest execution. This makes the test a lot more meaningful as it opens the door to exercising race conditions between #PF handling in the guest and save+restore in the host. The signals are ignored using SIG_IGN outside of __vcpu_run() to avoid interrupting other ioctls/sysctls performed by the test. Assisted-by: Gemini:gemini-3.1-pro Signed-off-by: Yosry Ahmed <yosry@kernel.org> Link: https://patch.msgid.link/20260728174232.2423257-12-yosry@kernel.org Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
committed by
Sean Christopherson
parent
d24dde74f7
commit
d99ad3c842
@@ -5,6 +5,8 @@
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "test_util.h"
|
||||
@@ -76,15 +78,41 @@ static void guest_access_memory(void *arg)
|
||||
/* Clear the present bit again so it faults next time */
|
||||
*guest_get_pte(vaddr) &= ~PTE_PRESENT_MASK(&guest_mmu);
|
||||
invlpg(vaddr);
|
||||
|
||||
GUEST_SYNC(guest_faults);
|
||||
}
|
||||
}
|
||||
|
||||
static void *sigusr_thread_fn(void *arg)
|
||||
{
|
||||
pthread_t vcpu_thread = (pthread_t)arg;
|
||||
|
||||
for (;;) {
|
||||
pthread_testcancel();
|
||||
pthread_kill(vcpu_thread, SIGUSR1);
|
||||
usleep(msecs_to_usecs(1));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dummy_signal_handler(int signo) {}
|
||||
static struct sigaction sa;
|
||||
|
||||
static void vcpu_sigusr_listen(void)
|
||||
{
|
||||
sa.sa_handler = dummy_signal_handler;
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
}
|
||||
|
||||
static void vcpu_sigusr_ignore(void)
|
||||
{
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct kvm_x86_state *state;
|
||||
int r, i, level;
|
||||
pthread_t sigusr_thread;
|
||||
gpa_t gpa, pgtable_gpa;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_vm *vm;
|
||||
@@ -128,18 +156,29 @@ int main(int argc, char *argv[])
|
||||
pgtable_gpa = PTE_GET_PA(pte);
|
||||
}
|
||||
|
||||
for (i = 1; i <= NR_ITERATIONS; i++) {
|
||||
r = __vcpu_run(vcpu);
|
||||
TEST_ASSERT(!r, "vcpu_run failed");
|
||||
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
|
||||
/* Initialize the thread sending SIGUSR and install the handler */
|
||||
vcpu_sigusr_ignore();
|
||||
r = pthread_create(&sigusr_thread, NULL, sigusr_thread_fn,
|
||||
(void *)pthread_self());
|
||||
TEST_ASSERT(!r, "pthread_create() failed: %d", r);
|
||||
|
||||
get_ucall(vcpu, &uc);
|
||||
if (uc.cmd == UCALL_ABORT) {
|
||||
for (i = 1; i <= NR_ITERATIONS; i++) {
|
||||
/*
|
||||
* Only handle SIGUSR while the vCPU is running, otherwise
|
||||
* ignore it to avoid interrupting other ioctls/syscalls.
|
||||
*/
|
||||
vcpu_sigusr_listen();
|
||||
r = __vcpu_run(vcpu);
|
||||
TEST_ASSERT(!r || errno == EINTR, "Expected success or SIGUSR1");
|
||||
vcpu_sigusr_ignore();
|
||||
|
||||
/* The guest only exits due to a signal or failed assertion */
|
||||
if (!r) {
|
||||
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
|
||||
TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_ABORT);
|
||||
REPORT_GUEST_ASSERT(uc);
|
||||
break;
|
||||
}
|
||||
TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC);
|
||||
TEST_ASSERT_EQ(uc.args[1], i);
|
||||
|
||||
state = vcpu_save_state(vcpu);
|
||||
|
||||
@@ -153,8 +192,11 @@ int main(int argc, char *argv[])
|
||||
pr_info("\n");
|
||||
|
||||
sync_global_from_guest(vm, guest_faults);
|
||||
TEST_ASSERT(guest_faults, "No guest page faults triggered");
|
||||
pr_info("Guest page faults: %lu\n", guest_faults);
|
||||
|
||||
pthread_cancel(sigusr_thread);
|
||||
pthread_join(sigusr_thread, NULL);
|
||||
kvm_vm_free(vm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user