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 * Copyright 2021 Oxide Computer Company 12 */ 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <unistd.h> 19 #include <sys/types.h> 20 21 #include <sys/vmm_dev.h> 22 23 static void 24 usage(const char *pname) 25 { 26 fprintf(stderr, 27 "Usage: %s [-a add] [-r remove] [-q]\n" 28 "\t-a <SZ> add SZ MiB to the reservoir\n" 29 "\t-r <SZ> remove SZ MiB from the reservoir\n" 30 "\t-q query reservoir state\n", pname); 31 } 32 33 static bool 34 parse_size(const char *arg, size_t *resp) 35 { 36 size_t res; 37 38 errno = 0; 39 res = strtoul(arg, NULL, 0); 40 if (errno != 0) { 41 return (false); 42 } 43 44 *resp = (res * 1024 * 1024); 45 return (true); 46 } 47 48 static void 49 do_add(int fd, size_t sz) 50 { 51 int res; 52 53 res = ioctl(fd, VMM_RESV_ADD, sz); 54 if (res != 0) { 55 perror("Could not add to reservoir"); 56 exit(EXIT_FAILURE); 57 } 58 } 59 60 static void 61 do_remove(int fd, size_t sz) 62 { 63 int res; 64 65 res = ioctl(fd, VMM_RESV_REMOVE, sz); 66 if (res != 0) { 67 perror("Could not remove from reservoir"); 68 exit(EXIT_FAILURE); 69 } 70 } 71 72 static void 73 do_query(int fd) 74 { 75 struct vmm_resv_query data; 76 int res; 77 78 res = ioctl(fd, VMM_RESV_QUERY, &data); 79 if (res != 0) { 80 perror("Could not query reservoir info"); 81 return; 82 } 83 84 printf("Free KiB:\t%llu\n" 85 "Allocated KiB:\t%llu\n" 86 "Transient Allocated KiB:\t%llu\n" 87 "Size limit KiB:\t%llu\n", 88 data.vrq_free_sz / 1024, 89 data.vrq_alloc_sz / 1024, 90 data.vrq_alloc_transient_sz / 1024, 91 data.vrq_limit / 1024); 92 } 93 94 int 95 main(int argc, char *argv[]) 96 { 97 char c; 98 const char *opt_a = NULL, *opt_r = NULL; 99 bool opt_q = false; 100 int fd; 101 102 const char *pname = argv[0]; 103 104 while ((c = getopt(argc, argv, "a:r:qh")) != -1) { 105 switch (c) { 106 case 'a': 107 opt_a = optarg; 108 break; 109 case 'r': 110 opt_r = optarg; 111 break; 112 case 'q': 113 opt_q = true; 114 break; 115 case 'h': 116 usage(pname); 117 return (EXIT_SUCCESS); 118 default: 119 usage(pname); 120 return (EXIT_FAILURE); 121 } 122 } 123 if (optind < argc || 124 (opt_a == NULL && opt_r == NULL && !opt_q) || 125 (opt_a != NULL && opt_r != NULL)) { 126 usage(pname); 127 return (EXIT_FAILURE); 128 } 129 130 fd = open(VMM_CTL_DEV, O_EXCL | O_RDWR); 131 if (fd < 0) { 132 perror("Could not open vmmctl"); 133 usage(pname); 134 return (EXIT_FAILURE); 135 } 136 137 if (opt_a != NULL) { 138 size_t sz; 139 140 if (!parse_size(opt_a, &sz)) { 141 perror("Invalid size"); 142 usage(pname); 143 return (EXIT_FAILURE); 144 } 145 146 do_add(fd, sz); 147 } 148 if (opt_r != NULL) { 149 size_t sz; 150 151 if (!parse_size(opt_r, &sz)) { 152 perror("Invalid size"); 153 usage(pname); 154 return (EXIT_FAILURE); 155 } 156 do_remove(fd, sz); 157 } 158 if (opt_q) { 159 do_query(fd); 160 } 161 162 (void) close(fd); 163 return (0); 164 } 165