1 // SPDX-License-Identifier: GPL-2.0-only
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
15 #include <test_util.h>
20 #define SLEEPING_THREAD_NUM (1 << 4)
21 #define FORK_NUM (1ULL << 9)
22 #define DELAY_US_MAX 2000
26 static void guest_code(void)
29 ; /* Some busy work */
30 printf("Should not be reached.\n");
33 static void *run_vcpu(void *arg
)
35 struct kvm_vcpu
*vcpu
= arg
;
36 struct kvm_run
*run
= vcpu
->run
;
40 TEST_ASSERT(false, "%s: exited with reason %d: %s",
41 __func__
, run
->exit_reason
,
42 exit_reason_str(run
->exit_reason
));
46 static void *sleeping_thread(void *arg
)
51 fd
= open("/dev/null", O_RDWR
);
54 TEST_ASSERT(false, "%s: exited", __func__
);
58 static inline void check_create_thread(pthread_t
*thread
, pthread_attr_t
*attr
,
59 void *(*f
)(void *), void *arg
)
63 r
= pthread_create(thread
, attr
, f
, arg
);
64 TEST_ASSERT(r
== 0, "%s: failed to create thread", __func__
);
67 static inline void check_set_affinity(pthread_t thread
, cpu_set_t
*cpu_set
)
71 r
= pthread_setaffinity_np(thread
, sizeof(cpu_set_t
), cpu_set
);
72 TEST_ASSERT(r
== 0, "%s: failed set affinity", __func__
);
75 static inline void check_join(pthread_t thread
, void **retval
)
79 r
= pthread_join(thread
, retval
);
80 TEST_ASSERT(r
== 0, "%s: failed to join thread", __func__
);
83 static void run_test(uint32_t run
)
85 struct kvm_vcpu
*vcpu
;
88 pthread_t threads
[VCPU_NUM
];
94 for (i
= 0; i
< VCPU_NUM
; i
++)
97 vm
= vm_create(VCPU_NUM
);
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
);
103 check_create_thread(&threads
[i
], NULL
, run_vcpu
, vcpu
);
104 check_set_affinity(threads
[i
], &cpu_set
);
106 for (j
= 0; j
< SLEEPING_THREAD_NUM
; ++j
) {
107 check_create_thread(&throw_away
, NULL
, sleeping_thread
,
109 check_set_affinity(throw_away
, &cpu_set
);
112 pr_debug("%s: [%d] all threads launched\n", __func__
, run
);
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
);
120 void wait_for_child_setup(pid_t pid
)
123 * Wait for the child to post to the semaphore, but wake up periodically
124 * to check if the child exited prematurely.
127 const struct timespec wait_period
= { .tv_sec
= 1 };
130 if (!sem_timedwait(sem
, &wait_period
))
133 /* Child is still running, keep waiting. */
134 if (pid
!= waitpid(pid
, &status
, WNOHANG
))
138 * Child is no longer running, which is not expected.
140 * If it exited with a non-zero status, we explicitly forward
141 * the child's status in case it exited with KSFT_SKIP.
143 if (WIFEXITED(status
))
144 exit(WEXITSTATUS(status
));
146 TEST_ASSERT(false, "Child exited unexpectedly");
150 int main(int argc
, char **argv
)
156 sem
= sem_open("vm_sem", O_CREAT
| O_EXCL
, 0644, 0);
157 sem_unlink("vm_sem");
159 for (i
= 0; i
< FORK_NUM
; ++i
) {
161 TEST_ASSERT(pid
>= 0, "%s: unable to fork", __func__
);
163 run_test(i
); /* This function always exits */
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
);
170 r
= waitpid(pid
, &s
, WNOHANG
);
171 TEST_ASSERT(r
!= pid
,
172 "%s: [%d] child exited unexpectedly status: [%d]",
174 pr_debug("%s: [%d] killing child\n", __func__
, i
);