Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/kvm/hardware_disable_test.c
38189 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* This test is intended to reproduce a crash that happens when
4
* kvm_arch_hardware_disable is called and it attempts to unregister the user
5
* return notifiers.
6
*/
7
#include <fcntl.h>
8
#include <pthread.h>
9
#include <semaphore.h>
10
#include <stdint.h>
11
#include <stdlib.h>
12
#include <unistd.h>
13
#include <sys/wait.h>
14
15
#include <test_util.h>
16
17
#include "kvm_util.h"
18
19
#define VCPU_NUM 4
20
#define SLEEPING_THREAD_NUM (1 << 4)
21
#define FORK_NUM (1ULL << 9)
22
#define DELAY_US_MAX 2000
23
24
sem_t *sem;
25
26
static void guest_code(void)
27
{
28
for (;;)
29
; /* Some busy work */
30
printf("Should not be reached.\n");
31
}
32
33
static void *run_vcpu(void *arg)
34
{
35
struct kvm_vcpu *vcpu = arg;
36
struct kvm_run *run = vcpu->run;
37
38
vcpu_run(vcpu);
39
40
TEST_ASSERT(false, "%s: exited with reason %d: %s",
41
__func__, run->exit_reason,
42
exit_reason_str(run->exit_reason));
43
pthread_exit(NULL);
44
}
45
46
static void *sleeping_thread(void *arg)
47
{
48
int fd;
49
50
while (true) {
51
fd = open("/dev/null", O_RDWR);
52
close(fd);
53
}
54
TEST_ASSERT(false, "%s: exited", __func__);
55
pthread_exit(NULL);
56
}
57
58
static inline void check_create_thread(pthread_t *thread, pthread_attr_t *attr,
59
void *(*f)(void *), void *arg)
60
{
61
int r;
62
63
r = pthread_create(thread, attr, f, arg);
64
TEST_ASSERT(r == 0, "%s: failed to create thread", __func__);
65
}
66
67
static inline void check_set_affinity(pthread_t thread, cpu_set_t *cpu_set)
68
{
69
int r;
70
71
r = pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpu_set);
72
TEST_ASSERT(r == 0, "%s: failed set affinity", __func__);
73
}
74
75
static inline void check_join(pthread_t thread, void **retval)
76
{
77
int r;
78
79
r = pthread_join(thread, retval);
80
TEST_ASSERT(r == 0, "%s: failed to join thread", __func__);
81
}
82
83
static void run_test(uint32_t run)
84
{
85
struct kvm_vcpu *vcpu;
86
struct kvm_vm *vm;
87
cpu_set_t cpu_set;
88
pthread_t threads[VCPU_NUM];
89
pthread_t throw_away;
90
void *b;
91
uint32_t i, j;
92
93
CPU_ZERO(&cpu_set);
94
for (i = 0; i < VCPU_NUM; i++)
95
CPU_SET(i, &cpu_set);
96
97
vm = vm_create(VCPU_NUM);
98
99
pr_debug("%s: [%d] start vcpus\n", __func__, run);
100
for (i = 0; i < VCPU_NUM; ++i) {
101
vcpu = vm_vcpu_add(vm, i, guest_code);
102
103
check_create_thread(&threads[i], NULL, run_vcpu, vcpu);
104
check_set_affinity(threads[i], &cpu_set);
105
106
for (j = 0; j < SLEEPING_THREAD_NUM; ++j) {
107
check_create_thread(&throw_away, NULL, sleeping_thread,
108
(void *)NULL);
109
check_set_affinity(throw_away, &cpu_set);
110
}
111
}
112
pr_debug("%s: [%d] all threads launched\n", __func__, run);
113
sem_post(sem);
114
for (i = 0; i < VCPU_NUM; ++i)
115
check_join(threads[i], &b);
116
/* Should not be reached */
117
TEST_ASSERT(false, "%s: [%d] child escaped the ninja", __func__, run);
118
}
119
120
void wait_for_child_setup(pid_t pid)
121
{
122
/*
123
* Wait for the child to post to the semaphore, but wake up periodically
124
* to check if the child exited prematurely.
125
*/
126
for (;;) {
127
const struct timespec wait_period = { .tv_sec = 1 };
128
int status;
129
130
if (!sem_timedwait(sem, &wait_period))
131
return;
132
133
/* Child is still running, keep waiting. */
134
if (pid != waitpid(pid, &status, WNOHANG))
135
continue;
136
137
/*
138
* Child is no longer running, which is not expected.
139
*
140
* If it exited with a non-zero status, we explicitly forward
141
* the child's status in case it exited with KSFT_SKIP.
142
*/
143
if (WIFEXITED(status))
144
exit(WEXITSTATUS(status));
145
else
146
TEST_ASSERT(false, "Child exited unexpectedly");
147
}
148
}
149
150
int main(int argc, char **argv)
151
{
152
uint32_t i;
153
int s, r;
154
pid_t pid;
155
156
sem = sem_open("vm_sem", O_CREAT | O_EXCL, 0644, 0);
157
sem_unlink("vm_sem");
158
159
for (i = 0; i < FORK_NUM; ++i) {
160
pid = fork();
161
TEST_ASSERT(pid >= 0, "%s: unable to fork", __func__);
162
if (pid == 0)
163
run_test(i); /* This function always exits */
164
165
pr_debug("%s: [%d] waiting semaphore\n", __func__, i);
166
wait_for_child_setup(pid);
167
r = (rand() % DELAY_US_MAX) + 1;
168
pr_debug("%s: [%d] waiting %dus\n", __func__, i, r);
169
usleep(r);
170
r = waitpid(pid, &s, WNOHANG);
171
TEST_ASSERT(r != pid,
172
"%s: [%d] child exited unexpectedly status: [%d]",
173
__func__, i, s);
174
pr_debug("%s: [%d] killing child\n", __func__, i);
175
kill(pid, SIGKILL);
176
}
177
178
sem_destroy(sem);
179
exit(0);
180
}
181
182