1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
7 #include <sys/linker.h>
11 #include <geom/gate/g_gate.h>
24 #include "ggate_drv.h"
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;
29 return ggio->gctl_seq;
32 int ggate_drv_req_cmd(ggate_drv_req_t req) {
33 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
35 switch (ggio->gctl_cmd) {
37 return GGATE_DRV_CMD_WRITE;
39 return GGATE_DRV_CMD_READ;
41 return GGATE_DRV_CMD_FLUSH;
43 return GGATE_DRV_CMD_DISCARD;
45 return GGATE_DRV_CMD_UNKNOWN;
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;
52 return ggio->gctl_offset;
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;
58 return ggio->gctl_length;
61 void *ggate_drv_req_buf(ggate_drv_req_t req) {
62 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
64 return ggio->gctl_data;
67 int ggate_drv_req_error(ggate_drv_req_t req) {
68 struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
70 return ggio->gctl_error;
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;
76 ggio->gctl_error = error;
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;
82 void *data = ggio->gctl_data;
83 ggio->gctl_data = NULL;
93 int ggate_drv_load() {
94 if (modfind("g_gate") != -1) {
95 /* Present in kernel. */
99 if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) {
100 if (errno != EEXIST) {
101 err("failed to load geom_gate module");
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;
113 debug(20, "%s: name=%s, sectorsize=%zd, mediasize=%zd, readonly=%d, info=%s",
114 __func__, name, sectorsize, mediasize, (int)readonly, info);
117 if (namelen > sizeof(ggiocreate.gctl_name) - 1) {
118 return -ENAMETOOLONG;
123 * We communicate with ggate via /dev/ggctl. Open it.
125 int fd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
127 err("failed to open /dev/" G_GATE_CTL_NAME);
131 drv = calloc(1, sizeof(*drv));
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;
148 ggiocreate.gctl_unit = G_GATE_NAME_GIVEN;
149 strlcpy(ggiocreate.gctl_name, name, sizeof(ggiocreate.gctl_name));
151 ggiocreate.gctl_unit = G_GATE_UNIT_AUTO;
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");
159 debug(20, "%s: created, unit: %d, name: %s", __func__, ggiocreate.gctl_unit,
160 ggiocreate.gctl_name);
163 drv->unit = ggiocreate.gctl_unit;
167 snprintf(name, namelen, "%s%d", G_GATE_PROVIDER_NAME, drv->unit);
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;
183 debug(20, "%s %p", __func__, drv);
185 memset(&ggiodestroy, 0, sizeof(ggiodestroy));
186 ggiodestroy.gctl_version = G_GATE_VERSION;
187 ggiodestroy.gctl_unit = drv->unit;
188 ggiodestroy.gctl_force = 1;
193 int r = ioctl(drv->fd, G_GATE_CMD_DESTROY, &ggiodestroy);
195 err("failed to destroy /dev/%s%d device", G_GATE_PROVIDER_NAME,
204 int ggate_drv_resize(ggate_drv_t drv_, size_t newsize) {
205 struct ggate_drv *drv = (struct ggate_drv *)drv_;
207 debug(20, "%s %p: newsize=%zd", __func__, drv, newsize);
209 struct g_gate_ctl_modify ggiomodify;
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;
217 int r = ioctl(drv->fd, G_GATE_CMD_MODIFY, &ggiomodify);
220 err("failed to resize /dev/%s%d device", G_GATE_PROVIDER_NAME, drv->unit);
225 int ggate_drv_kill(const char *devname) {
226 debug(20, "%s %s", __func__, devname);
228 int fd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
230 err("failed to open /dev/" G_GATE_CTL_NAME);
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;
240 strlcpy(ggiodestroy.gctl_name, devname, sizeof(ggiodestroy.gctl_name));
242 int r = ioctl(fd, G_GATE_CMD_DESTROY, &ggiodestroy);
245 err("failed to destroy %s device", devname);
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;
257 debug(20, "%s", __func__);
259 ggio = calloc(1, sizeof(*ggio));
264 ggio->gctl_version = G_GATE_VERSION;
265 ggio->gctl_unit = drv->unit;
266 ggio->gctl_data = malloc(MAXPHYS);
267 ggio->gctl_length = MAXPHYS;
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__);
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);
281 error = ggio->gctl_error;
286 debug(10, "%s: canceled: exit gracefully", __func__);
291 * Buffer too small? Impossible, we allocate MAXPHYS
292 * bytes - request can't be bigger than that.
298 err("%s: G_GATE_CMD_START failed", __func__);
307 free(ggio->gctl_data);
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;
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);
323 if (ioctl(drv->fd, G_GATE_CMD_DONE, ggio) == -1) {
324 err("%s: G_GATE_CMD_DONE failed", __func__);
328 free(ggio->gctl_data);
333 int ggate_drv_list(char **devs, size_t *size) {
335 struct gclass *class;
340 r = geom_gettree(&mesh);
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) {
353 if (*size > max_size) {
357 LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
358 *devs = strdup(gp->lg_name);
365 geom_deletetree(&mesh);
369 void ggate_drv_list_free(char **devs, size_t size) {
372 for (i = 0; i < size; i++) {