]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_ggate/ggate_drv.c
update sources to v12.1.3
[ceph.git] / ceph / src / tools / rbd_ggate / ggate_drv.c
1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <sys/param.h>
5 #include <sys/bio.h>
6 #include <sys/disk.h>
7 #include <sys/linker.h>
8 #include <sys/queue.h>
9 #include <sys/stat.h>
10
11 #include <geom/gate/g_gate.h>
12
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdarg.h>
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <libgeom.h>
22
23 #include "debug.h"
24 #include "ggate_drv.h"
25
26 uint64_t ggate_drv_req_id(ggate_drv_req_t req) {
27 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
28
29 return ggio->gctl_seq;
30 }
31
32 int ggate_drv_req_cmd(ggate_drv_req_t req) {
33 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
34
35 switch (ggio->gctl_cmd) {
36 case BIO_WRITE:
37 return GGATE_DRV_CMD_WRITE;
38 case BIO_READ:
39 return GGATE_DRV_CMD_READ;
40 case BIO_FLUSH:
41 return GGATE_DRV_CMD_FLUSH;
42 case BIO_DELETE:
43 return GGATE_DRV_CMD_DISCARD;
44 default:
45 return GGATE_DRV_CMD_UNKNOWN;
46 }
47 }
48
49 uint64_t ggate_drv_req_offset(ggate_drv_req_t req) {
50 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
51
52 return ggio->gctl_offset;
53 }
54
55 size_t ggate_drv_req_length(ggate_drv_req_t req) {
56 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
57
58 return ggio->gctl_length;
59 }
60
61 void *ggate_drv_req_buf(ggate_drv_req_t req) {
62 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
63
64 return ggio->gctl_data;
65 }
66
67 int ggate_drv_req_error(ggate_drv_req_t req) {
68 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
69
70 return ggio->gctl_error;
71 }
72
73 void ggate_drv_req_set_error(ggate_drv_req_t req, int error) {
74 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
75
76 ggio->gctl_error = error;
77 }
78
79 void *ggate_drv_req_release_buf(ggate_drv_req_t req) {
80 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
81
82 void *data = ggio->gctl_data;
83 ggio->gctl_data = NULL;
84
85 return data;
86 }
87
88 struct ggate_drv {
89 int fd;
90 int unit;
91 };
92
93 int ggate_drv_load() {
94 if (modfind("g_gate") != -1) {
95 /* Present in kernel. */
96 return 0;
97 }
98
99 if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) {
100 if (errno != EEXIST) {
101 err("failed to load geom_gate module");
102 return -errno;
103 }
104 }
105 return 0;
106 }
107
108 int ggate_drv_create(char *name, size_t namelen, size_t sectorsize,
109 size_t mediasize, bool readonly, const char *info, ggate_drv_t *drv_) {
110 struct ggate_drv *drv;
111 struct g_gate_ctl_create ggiocreate;
112
113 debug(20, "%s: name=%s, sectorsize=%zd, mediasize=%zd, readonly=%d, info=%s",
114 __func__, name, sectorsize, mediasize, (int)readonly, info);
115
116 if (*name != '\0') {
117 if (namelen > sizeof(ggiocreate.gctl_name) - 1) {
118 return -ENAMETOOLONG;
119 }
120 }
121
122 /*
123 * We communicate with ggate via /dev/ggctl. Open it.
124 */
125 int fd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
126 if (fd == -1) {
127 err("failed to open /dev/" G_GATE_CTL_NAME);
128 return -errno;
129 }
130
131 drv = calloc(1, sizeof(*drv));
132 if (drv == NULL) {
133 errno = -ENOMEM;
134 goto fail_close;
135 }
136
137 /*
138 * Create provider.
139 */
140 memset(&ggiocreate, 0, sizeof(ggiocreate));
141 ggiocreate.gctl_version = G_GATE_VERSION;
142 ggiocreate.gctl_mediasize = mediasize;
143 ggiocreate.gctl_sectorsize = sectorsize;
144 ggiocreate.gctl_flags = readonly ? G_GATE_FLAG_READONLY : 0;
145 ggiocreate.gctl_maxcount = 0;
146 ggiocreate.gctl_timeout = 0;
147 if (*name != '\0') {
148 ggiocreate.gctl_unit = G_GATE_NAME_GIVEN;
149 strlcpy(ggiocreate.gctl_name, name, sizeof(ggiocreate.gctl_name));
150 } else {
151 ggiocreate.gctl_unit = G_GATE_UNIT_AUTO;
152 }
153 strlcpy(ggiocreate.gctl_info, info, sizeof(ggiocreate.gctl_info));
154 if (ioctl(fd, G_GATE_CMD_CREATE, &ggiocreate) == -1) {
155 err("failed to create " G_GATE_PROVIDER_NAME " device");
156 goto fail;
157 }
158
159 debug(20, "%s: created, unit: %d, name: %s", __func__, ggiocreate.gctl_unit,
160 ggiocreate.gctl_name);
161
162 drv->fd = fd;
163 drv->unit = ggiocreate.gctl_unit;
164 *drv_ = drv;
165
166 if (*name == '\0') {
167 snprintf(name, namelen, "%s%d", G_GATE_PROVIDER_NAME, drv->unit);
168 }
169
170 return 0;
171
172 fail:
173 free(drv);
174 fail_close:
175 close(fd);
176 return -errno;
177 }
178
179 void ggate_drv_destroy(ggate_drv_t drv_) {
180 struct ggate_drv *drv = (struct ggate_drv *)drv_;
181 struct g_gate_ctl_destroy ggiodestroy;
182
183 debug(20, "%s %p", __func__, drv);
184
185 memset(&ggiodestroy, 0, sizeof(ggiodestroy));
186 ggiodestroy.gctl_version = G_GATE_VERSION;
187 ggiodestroy.gctl_unit = drv->unit;
188 ggiodestroy.gctl_force = 1;
189
190 // Remember errno.
191 int rerrno = errno;
192
193 int r = ioctl(drv->fd, G_GATE_CMD_DESTROY, &ggiodestroy);
194 if (r == -1) {
195 err("failed to destroy /dev/%s%d device", G_GATE_PROVIDER_NAME,
196 drv->unit);
197 }
198 // Restore errno.
199 errno = rerrno;
200
201 free(drv);
202 }
203
204 int ggate_drv_resize(ggate_drv_t drv_, size_t newsize) {
205 struct ggate_drv *drv = (struct ggate_drv *)drv_;
206
207 debug(20, "%s %p: newsize=%zd", __func__, drv, newsize);
208
209 struct g_gate_ctl_modify ggiomodify;
210
211 memset(&ggiomodify, 0, sizeof(ggiomodify));
212 ggiomodify.gctl_version = G_GATE_VERSION;
213 ggiomodify.gctl_unit = drv->unit;
214 ggiomodify.gctl_modify = GG_MODIFY_MEDIASIZE;
215 ggiomodify.gctl_mediasize = newsize;
216
217 int r = ioctl(drv->fd, G_GATE_CMD_MODIFY, &ggiomodify);
218 if (r == -1) {
219 r = -errno;
220 err("failed to resize /dev/%s%d device", G_GATE_PROVIDER_NAME, drv->unit);
221 }
222 return r;
223 }
224
225 int ggate_drv_kill(const char *devname) {
226 debug(20, "%s %s", __func__, devname);
227
228 int fd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
229 if (fd == -1) {
230 err("failed to open /dev/" G_GATE_CTL_NAME);
231 return -errno;
232 }
233
234 struct g_gate_ctl_destroy ggiodestroy;
235 memset(&ggiodestroy, 0, sizeof(ggiodestroy));
236 ggiodestroy.gctl_version = G_GATE_VERSION;
237 ggiodestroy.gctl_unit = G_GATE_NAME_GIVEN;
238 ggiodestroy.gctl_force = 1;
239
240 strlcpy(ggiodestroy.gctl_name, devname, sizeof(ggiodestroy.gctl_name));
241
242 int r = ioctl(fd, G_GATE_CMD_DESTROY, &ggiodestroy);
243 if (r == -1) {
244 r = -errno;
245 err("failed to destroy %s device", devname);
246 }
247
248 close(fd);
249 return r;
250 }
251
252 int ggate_drv_recv(ggate_drv_t drv_, ggate_drv_req_t *req) {
253 struct ggate_drv *drv = (struct ggate_drv *)drv_;
254 struct g_gate_ctl_io *ggio;
255 int error, r;
256
257 debug(20, "%s", __func__);
258
259 ggio = calloc(1, sizeof(*ggio));
260 if (ggio == NULL) {
261 return -ENOMEM;
262 }
263
264 ggio->gctl_version = G_GATE_VERSION;
265 ggio->gctl_unit = drv->unit;
266 ggio->gctl_data = malloc(MAXPHYS);
267 ggio->gctl_length = MAXPHYS;
268
269 debug(20, "%s: waiting for request from kernel", __func__);
270 if (ioctl(drv->fd, G_GATE_CMD_START, ggio) == -1) {
271 err("%s: G_GATE_CMD_START failed", __func__);
272 return -errno;
273 }
274
275 debug(20, "%s: got request from kernel: "
276 "unit=%d, seq=%ju, cmd=%u, offset=%ju, length=%ju, error=%d, data=%p",
277 __func__, ggio->gctl_unit, (uintmax_t)ggio->gctl_seq, ggio->gctl_cmd,
278 (uintmax_t)ggio->gctl_offset, (uintmax_t)ggio->gctl_length,
279 ggio->gctl_error, ggio->gctl_data);
280
281 error = ggio->gctl_error;
282 switch (error) {
283 case 0:
284 break;
285 case ECANCELED:
286 debug(10, "%s: canceled: exit gracefully", __func__);
287 r = -error;
288 goto fail;
289 case ENOMEM:
290 /*
291 * Buffer too small? Impossible, we allocate MAXPHYS
292 * bytes - request can't be bigger than that.
293 */
294 /* FALLTHROUGH */
295 case ENXIO:
296 default:
297 errno = error;
298 err("%s: G_GATE_CMD_START failed", __func__);
299 r = -error;
300 goto fail;
301 }
302
303 *req = ggio;
304 return 0;
305
306 fail:
307 free(ggio->gctl_data);
308 free(ggio);
309 return r;
310 }
311
312 int ggate_drv_send(ggate_drv_t drv_, ggate_drv_req_t req) {
313 struct ggate_drv *drv = (struct ggate_drv *)drv_;
314 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
315 int r = 0;
316
317 debug(20, "%s: send request to kernel: "
318 "unit=%d, seq=%ju, cmd=%u, offset=%ju, length=%ju, error=%d, data=%p",
319 __func__, ggio->gctl_unit, (uintmax_t)ggio->gctl_seq, ggio->gctl_cmd,
320 (uintmax_t)ggio->gctl_offset, (uintmax_t)ggio->gctl_length,
321 ggio->gctl_error, ggio->gctl_data);
322
323 if (ioctl(drv->fd, G_GATE_CMD_DONE, ggio) == -1) {
324 err("%s: G_GATE_CMD_DONE failed", __func__);
325 r = -errno;
326 }
327
328 free(ggio->gctl_data);
329 free(ggio);
330 return r;
331 }
332
333 int ggate_drv_list(char **devs, size_t *size) {
334 struct gmesh mesh;
335 struct gclass *class;
336 struct ggeom *gp;
337 int r;
338 size_t max_size;
339
340 r = geom_gettree(&mesh);
341 if (r != 0) {
342 return -errno;
343 }
344
345 max_size = *size;
346 *size = 0;
347
348 LIST_FOREACH(class, &mesh.lg_class, lg_class) {
349 if (strcmp(class->lg_name, G_GATE_CLASS_NAME) == 0) {
350 LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
351 (*size)++;
352 }
353 if (*size > max_size) {
354 r = -ERANGE;
355 goto done;
356 }
357 LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
358 *devs = strdup(gp->lg_name);
359 devs++;
360 }
361 }
362 }
363
364 done:
365 geom_deletetree(&mesh);
366 return r;
367 }
368
369 void ggate_drv_list_free(char **devs, size_t size) {
370 size_t i;
371
372 for (i = 0; i < size; i++) {
373 free(devs[i]);
374 }
375 }