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
++) {