Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | // SPDX-License-Identifier: GPL-2.0-only /* * This test is intended to reproduce a crash that happens when * kvm_arch_hardware_disable is called and it attempts to unregister the user * return notifiers. */ #define _GNU_SOURCE #include <fcntl.h> #include <pthread.h> #include <semaphore.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <test_util.h> #include "kvm_util.h" #define VCPU_NUM 4 #define SLEEPING_THREAD_NUM (1 << 4) #define FORK_NUM (1ULL << 9) #define DELAY_US_MAX 2000 #define GUEST_CODE_PIO_PORT 4 sem_t *sem; /* Arguments for the pthreads */ struct payload { struct kvm_vm *vm; uint32_t index; }; static void guest_code(void) { for (;;) ; /* Some busy work */ printf("Should not be reached.\n"); } static void *run_vcpu(void *arg) { struct payload *payload = (struct payload *)arg; struct kvm_run *state = vcpu_state(payload->vm, payload->index); vcpu_run(payload->vm, payload->index); TEST_ASSERT(false, "%s: exited with reason %d: %s\n", __func__, state->exit_reason, exit_reason_str(state->exit_reason)); pthread_exit(NULL); } static void *sleeping_thread(void *arg) { int fd; while (true) { fd = open("/dev/null", O_RDWR); close(fd); } TEST_ASSERT(false, "%s: exited\n", __func__); pthread_exit(NULL); } static inline void check_create_thread(pthread_t *thread, pthread_attr_t *attr, void *(*f)(void *), void *arg) { int r; r = pthread_create(thread, attr, f, arg); TEST_ASSERT(r == 0, "%s: failed to create thread", __func__); } static inline void check_set_affinity(pthread_t thread, cpu_set_t *cpu_set) { int r; r = pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpu_set); TEST_ASSERT(r == 0, "%s: failed set affinity", __func__); } static inline void check_join(pthread_t thread, void **retval) { int r; r = pthread_join(thread, retval); TEST_ASSERT(r == 0, "%s: failed to join thread", __func__); } static void run_test(uint32_t run) { struct kvm_vm *vm; cpu_set_t cpu_set; pthread_t threads[VCPU_NUM]; pthread_t throw_away; struct payload payloads[VCPU_NUM]; void *b; uint32_t i, j; CPU_ZERO(&cpu_set); for (i = 0; i < VCPU_NUM; i++) CPU_SET(i, &cpu_set); vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); kvm_vm_elf_load(vm, program_invocation_name, 0, 0); vm_create_irqchip(vm); fprintf(stderr, "%s: [%d] start vcpus\n", __func__, run); for (i = 0; i < VCPU_NUM; ++i) { vm_vcpu_add_default(vm, i, guest_code); payloads[i].vm = vm; payloads[i].index = i; check_create_thread(&threads[i], NULL, run_vcpu, (void *)&payloads[i]); check_set_affinity(threads[i], &cpu_set); for (j = 0; j < SLEEPING_THREAD_NUM; ++j) { check_create_thread(&throw_away, NULL, sleeping_thread, (void *)NULL); check_set_affinity(throw_away, &cpu_set); } } fprintf(stderr, "%s: [%d] all threads launched\n", __func__, run); sem_post(sem); for (i = 0; i < VCPU_NUM; ++i) check_join(threads[i], &b); /* Should not be reached */ TEST_ASSERT(false, "%s: [%d] child escaped the ninja\n", __func__, run); } int main(int argc, char **argv) { uint32_t i; int s, r; pid_t pid; sem = sem_open("vm_sem", O_CREAT | O_EXCL, 0644, 0); sem_unlink("vm_sem"); for (i = 0; i < FORK_NUM; ++i) { pid = fork(); TEST_ASSERT(pid >= 0, "%s: unable to fork", __func__); if (pid == 0) run_test(i); /* This function always exits */ fprintf(stderr, "%s: [%d] waiting semaphore\n", __func__, i); sem_wait(sem); r = (rand() % DELAY_US_MAX) + 1; fprintf(stderr, "%s: [%d] waiting %dus\n", __func__, i, r); usleep(r); r = waitpid(pid, &s, WNOHANG); TEST_ASSERT(r != pid, "%s: [%d] child exited unexpectedly status: [%d]", __func__, i, s); fprintf(stderr, "%s: [%d] killing child\n", __func__, i); kill(pid, SIGKILL); } sem_destroy(sem); exit(0); } |