Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * This test is intended to reproduce a crash that happens when
0004  * kvm_arch_hardware_disable is called and it attempts to unregister the user
0005  * return notifiers.
0006  */
0007 
0008 #define _GNU_SOURCE
0009 
0010 #include <fcntl.h>
0011 #include <pthread.h>
0012 #include <semaphore.h>
0013 #include <stdint.h>
0014 #include <stdlib.h>
0015 #include <unistd.h>
0016 #include <sys/wait.h>
0017 
0018 #include <test_util.h>
0019 
0020 #include "kvm_util.h"
0021 
0022 #define VCPU_NUM 4
0023 #define SLEEPING_THREAD_NUM (1 << 4)
0024 #define FORK_NUM (1ULL << 9)
0025 #define DELAY_US_MAX 2000
0026 #define GUEST_CODE_PIO_PORT 4
0027 
0028 sem_t *sem;
0029 
0030 static void guest_code(void)
0031 {
0032     for (;;)
0033         ;  /* Some busy work */
0034     printf("Should not be reached.\n");
0035 }
0036 
0037 static void *run_vcpu(void *arg)
0038 {
0039     struct kvm_vcpu *vcpu = arg;
0040     struct kvm_run *run = vcpu->run;
0041 
0042     vcpu_run(vcpu);
0043 
0044     TEST_ASSERT(false, "%s: exited with reason %d: %s\n",
0045             __func__, run->exit_reason,
0046             exit_reason_str(run->exit_reason));
0047     pthread_exit(NULL);
0048 }
0049 
0050 static void *sleeping_thread(void *arg)
0051 {
0052     int fd;
0053 
0054     while (true) {
0055         fd = open("/dev/null", O_RDWR);
0056         close(fd);
0057     }
0058     TEST_ASSERT(false, "%s: exited\n", __func__);
0059     pthread_exit(NULL);
0060 }
0061 
0062 static inline void check_create_thread(pthread_t *thread, pthread_attr_t *attr,
0063                        void *(*f)(void *), void *arg)
0064 {
0065     int r;
0066 
0067     r = pthread_create(thread, attr, f, arg);
0068     TEST_ASSERT(r == 0, "%s: failed to create thread", __func__);
0069 }
0070 
0071 static inline void check_set_affinity(pthread_t thread, cpu_set_t *cpu_set)
0072 {
0073     int r;
0074 
0075     r = pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpu_set);
0076     TEST_ASSERT(r == 0, "%s: failed set affinity", __func__);
0077 }
0078 
0079 static inline void check_join(pthread_t thread, void **retval)
0080 {
0081     int r;
0082 
0083     r = pthread_join(thread, retval);
0084     TEST_ASSERT(r == 0, "%s: failed to join thread", __func__);
0085 }
0086 
0087 static void run_test(uint32_t run)
0088 {
0089     struct kvm_vcpu *vcpu;
0090     struct kvm_vm *vm;
0091     cpu_set_t cpu_set;
0092     pthread_t threads[VCPU_NUM];
0093     pthread_t throw_away;
0094     void *b;
0095     uint32_t i, j;
0096 
0097     CPU_ZERO(&cpu_set);
0098     for (i = 0; i < VCPU_NUM; i++)
0099         CPU_SET(i, &cpu_set);
0100 
0101     vm = vm_create(VCPU_NUM);
0102 
0103     pr_debug("%s: [%d] start vcpus\n", __func__, run);
0104     for (i = 0; i < VCPU_NUM; ++i) {
0105         vcpu = vm_vcpu_add(vm, i, guest_code);
0106 
0107         check_create_thread(&threads[i], NULL, run_vcpu, vcpu);
0108         check_set_affinity(threads[i], &cpu_set);
0109 
0110         for (j = 0; j < SLEEPING_THREAD_NUM; ++j) {
0111             check_create_thread(&throw_away, NULL, sleeping_thread,
0112                         (void *)NULL);
0113             check_set_affinity(throw_away, &cpu_set);
0114         }
0115     }
0116     pr_debug("%s: [%d] all threads launched\n", __func__, run);
0117     sem_post(sem);
0118     for (i = 0; i < VCPU_NUM; ++i)
0119         check_join(threads[i], &b);
0120     /* Should not be reached */
0121     TEST_ASSERT(false, "%s: [%d] child escaped the ninja\n", __func__, run);
0122 }
0123 
0124 void wait_for_child_setup(pid_t pid)
0125 {
0126     /*
0127      * Wait for the child to post to the semaphore, but wake up periodically
0128      * to check if the child exited prematurely.
0129      */
0130     for (;;) {
0131         const struct timespec wait_period = { .tv_sec = 1 };
0132         int status;
0133 
0134         if (!sem_timedwait(sem, &wait_period))
0135             return;
0136 
0137         /* Child is still running, keep waiting. */
0138         if (pid != waitpid(pid, &status, WNOHANG))
0139             continue;
0140 
0141         /*
0142          * Child is no longer running, which is not expected.
0143          *
0144          * If it exited with a non-zero status, we explicitly forward
0145          * the child's status in case it exited with KSFT_SKIP.
0146          */
0147         if (WIFEXITED(status))
0148             exit(WEXITSTATUS(status));
0149         else
0150             TEST_ASSERT(false, "Child exited unexpectedly");
0151     }
0152 }
0153 
0154 int main(int argc, char **argv)
0155 {
0156     uint32_t i;
0157     int s, r;
0158     pid_t pid;
0159 
0160     sem = sem_open("vm_sem", O_CREAT | O_EXCL, 0644, 0);
0161     sem_unlink("vm_sem");
0162 
0163     for (i = 0; i < FORK_NUM; ++i) {
0164         pid = fork();
0165         TEST_ASSERT(pid >= 0, "%s: unable to fork", __func__);
0166         if (pid == 0)
0167             run_test(i); /* This function always exits */
0168 
0169         pr_debug("%s: [%d] waiting semaphore\n", __func__, i);
0170         wait_for_child_setup(pid);
0171         r = (rand() % DELAY_US_MAX) + 1;
0172         pr_debug("%s: [%d] waiting %dus\n", __func__, i, r);
0173         usleep(r);
0174         r = waitpid(pid, &s, WNOHANG);
0175         TEST_ASSERT(r != pid,
0176                 "%s: [%d] child exited unexpectedly status: [%d]",
0177                 __func__, i, s);
0178         pr_debug("%s: [%d] killing child\n", __func__, i);
0179         kill(pid, SIGKILL);
0180     }
0181 
0182     sem_destroy(sem);
0183     exit(0);
0184 }