xref: /illumos-gate/usr/src/cmd/rsrvrctl/rsrvrctl.c (revision b57f5d3e)
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