Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 }