1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2022 Oxide Computer Company 14 */ 15 16 #include <stdio.h> 17 #include <unistd.h> 18 #include <stdlib.h> 19 #include <fcntl.h> 20 #include <libgen.h> 21 #include <sys/stat.h> 22 #include <errno.h> 23 #include <assert.h> 24 25 #include <sys/vmm.h> 26 #include <sys/vmm_dev.h> 27 #include <sys/vmm_drv_test.h> 28 #include <vmmapi.h> 29 30 #include "common.h" 31 32 bool 33 test_for_instance(const char *suite_name) 34 { 35 char vm_name[VM_MAX_NAMELEN]; 36 char vm_path[MAXPATHLEN]; 37 38 name_test_vm(suite_name, vm_name); 39 (void) snprintf(vm_path, sizeof (vm_path), "/dev/vmm/%s", vm_name); 40 41 struct stat buf; 42 return (stat(vm_path, &buf) == 0); 43 } 44 45 int 46 destroy_instance(const char *suite_name) 47 { 48 int ctl_fd = open(VMM_CTL_DEV, O_EXCL | O_RDWR); 49 if (ctl_fd < 0) { 50 return (-1); 51 } 52 53 struct vm_destroy_req req; 54 name_test_vm(suite_name, req.name); 55 56 if (ioctl(ctl_fd, VMM_DESTROY_VM, &req) != 0) { 57 /* Preserve the destroy error across the close() */ 58 int err = errno; 59 (void) close(ctl_fd); 60 errno = err; 61 return (-1); 62 } else { 63 (void) close(ctl_fd); 64 return (0); 65 } 66 } 67 68 int 69 main(int argc, char *argv[]) 70 { 71 const char *suite_name = basename(argv[0]); 72 struct vmctx *ctx; 73 74 ctx = create_test_vm(suite_name); 75 if (ctx == NULL) { 76 perror("could open test VM"); 77 return (EXIT_FAILURE); 78 } 79 80 /* 81 * It would be odd if we had the freshly created VM instance, but it did 82 * not appear to exist. 83 */ 84 assert(test_for_instance(suite_name)); 85 86 /* Make sure that auto-destruct is off */ 87 if (ioctl(vm_get_device_fd(ctx), VM_SET_AUTODESTRUCT, 0) != 0) { 88 perror("could not disable auto-destruct"); 89 return (EXIT_FAILURE); 90 } 91 92 vm_close(ctx); 93 if (!test_for_instance(suite_name)) { 94 perror("instance missing after close"); 95 return (EXIT_FAILURE); 96 } 97 ctx = NULL; 98 99 if (destroy_instance(suite_name) != 0) { 100 perror("could not clean up instance"); 101 return (EXIT_FAILURE); 102 } 103 104 /* Now repeat that process, but enable auto-destruct */ 105 ctx = create_test_vm(suite_name); 106 if (ctx == NULL) { 107 perror("could open test VM"); 108 return (EXIT_FAILURE); 109 } 110 if (ioctl(vm_get_device_fd(ctx), VM_SET_AUTODESTRUCT, 1) != 0) { 111 perror("could not enable auto-destruct"); 112 return (EXIT_FAILURE); 113 } 114 vm_close(ctx); 115 ctx = NULL; 116 /* At this point, the instance should be gone */ 117 if (test_for_instance(suite_name)) { 118 (void) fprintf(stderr, 119 "instance did not auto-destruct as expected"); 120 return (EXIT_FAILURE); 121 } 122 123 /* 124 * Repeat the test again, but establish a vmm_drv hold first. 125 * The instance should auto-destruct when the hold is released. 126 */ 127 ctx = create_test_vm(suite_name); 128 if (ctx == NULL) { 129 perror("could open test VM"); 130 return (EXIT_FAILURE); 131 } 132 if (ioctl(vm_get_device_fd(ctx), VM_SET_AUTODESTRUCT, 1) != 0) { 133 perror("could not enable auto-destruct"); 134 return (EXIT_FAILURE); 135 } 136 int vdtfd = open_drv_test(); 137 if (vdtfd < 0) { 138 perror("could open drv_test device"); 139 return (EXIT_FAILURE); 140 } 141 if (ioctl(vdtfd, VDT_IOC_HOLD, vm_get_device_fd(ctx)) != 0) { 142 perror("could not hold VM from vmm_drv device"); 143 return (EXIT_FAILURE); 144 } 145 vm_close(ctx); 146 ctx = NULL; 147 if (!test_for_instance(suite_name)) { 148 (void) fprintf(stderr, 149 "instance auto-destructed despite existing vmm_drv hold"); 150 return (EXIT_FAILURE); 151 } 152 if (ioctl(vdtfd, VDT_IOC_RELE, 0) != 0) { 153 perror("could not release VM from vmm_drv device"); 154 return (EXIT_FAILURE); 155 } 156 if (test_for_instance(suite_name)) { 157 (void) fprintf(stderr, 158 "instance did not auto-destructed after vmm_drv release"); 159 return (EXIT_FAILURE); 160 } 161 162 (void) printf("%s\tPASS\n", suite_name); 163 return (EXIT_SUCCESS); 164 } 165