+++ /dev/null
-// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include <sys/param.h>
-#include <sys/bio.h>
-#include <sys/disk.h>
-#include <sys/linker.h>
-#include <sys/queue.h>
-#include <sys/stat.h>
-
-#include <geom/gate/g_gate.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <libgeom.h>
-
-#include "debug.h"
-#include "ggate_drv.h"
-
-uint64_t ggate_drv_req_id(ggate_drv_req_t req) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- return ggio->gctl_seq;
-}
-
-int ggate_drv_req_cmd(ggate_drv_req_t req) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- switch (ggio->gctl_cmd) {
- case BIO_WRITE:
- return GGATE_DRV_CMD_WRITE;
- case BIO_READ:
- return GGATE_DRV_CMD_READ;
- case BIO_FLUSH:
- return GGATE_DRV_CMD_FLUSH;
- case BIO_DELETE:
- return GGATE_DRV_CMD_DISCARD;
- default:
- return GGATE_DRV_CMD_UNKNOWN;
- }
-}
-
-uint64_t ggate_drv_req_offset(ggate_drv_req_t req) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- return ggio->gctl_offset;
-}
-
-size_t ggate_drv_req_length(ggate_drv_req_t req) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- return ggio->gctl_length;
-}
-
-void *ggate_drv_req_buf(ggate_drv_req_t req) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- return ggio->gctl_data;
-}
-
-int ggate_drv_req_error(ggate_drv_req_t req) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- return ggio->gctl_error;
-}
-
-void ggate_drv_req_set_error(ggate_drv_req_t req, int error) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- ggio->gctl_error = error;
-}
-
-void *ggate_drv_req_release_buf(ggate_drv_req_t req) {
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
-
- void *data = ggio->gctl_data;
- ggio->gctl_data = NULL;
-
- return data;
-}
-
-struct ggate_drv {
- int fd;
- int unit;
-};
-
-int ggate_drv_load() {
- if (modfind("g_gate") != -1) {
- /* Present in kernel. */
- return 0;
- }
-
- if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) {
- if (errno != EEXIST) {
- err("failed to load geom_gate module");
- return -errno;
- }
- }
- return 0;
-}
-
-int ggate_drv_create(char *name, size_t namelen, size_t sectorsize,
- size_t mediasize, bool readonly, const char *info, ggate_drv_t *drv_) {
- struct ggate_drv *drv;
- struct g_gate_ctl_create ggiocreate;
-
- debug(20, "%s: name=%s, sectorsize=%zd, mediasize=%zd, readonly=%d, info=%s",
- __func__, name, sectorsize, mediasize, (int)readonly, info);
-
- if (*name != '\0') {
- if (namelen > sizeof(ggiocreate.gctl_name) - 1) {
- return -ENAMETOOLONG;
- }
- }
-
- /*
- * We communicate with ggate via /dev/ggctl. Open it.
- */
- int fd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
- if (fd == -1) {
- err("failed to open /dev/" G_GATE_CTL_NAME);
- return -errno;
- }
-
- drv = calloc(1, sizeof(*drv));
- if (drv == NULL) {
- errno = -ENOMEM;
- goto fail_close;
- }
-
- /*
- * Create provider.
- */
- memset(&ggiocreate, 0, sizeof(ggiocreate));
- ggiocreate.gctl_version = G_GATE_VERSION;
- ggiocreate.gctl_mediasize = mediasize;
- ggiocreate.gctl_sectorsize = sectorsize;
- ggiocreate.gctl_flags = readonly ? G_GATE_FLAG_READONLY : 0;
- ggiocreate.gctl_maxcount = 0;
- ggiocreate.gctl_timeout = 0;
- if (*name != '\0') {
- ggiocreate.gctl_unit = G_GATE_NAME_GIVEN;
- strlcpy(ggiocreate.gctl_name, name, sizeof(ggiocreate.gctl_name));
- } else {
- ggiocreate.gctl_unit = G_GATE_UNIT_AUTO;
- }
- strlcpy(ggiocreate.gctl_info, info, sizeof(ggiocreate.gctl_info));
- if (ioctl(fd, G_GATE_CMD_CREATE, &ggiocreate) == -1) {
- err("failed to create " G_GATE_PROVIDER_NAME " device");
- goto fail;
- }
-
- debug(20, "%s: created, unit: %d, name: %s", __func__, ggiocreate.gctl_unit,
- ggiocreate.gctl_name);
-
- drv->fd = fd;
- drv->unit = ggiocreate.gctl_unit;
- *drv_ = drv;
-
- if (*name == '\0') {
- snprintf(name, namelen, "%s%d", G_GATE_PROVIDER_NAME, drv->unit);
- }
-
- return 0;
-
-fail:
- free(drv);
-fail_close:
- close(fd);
- return -errno;
-}
-
-void ggate_drv_destroy(ggate_drv_t drv_) {
- struct ggate_drv *drv = (struct ggate_drv *)drv_;
- struct g_gate_ctl_destroy ggiodestroy;
-
- debug(20, "%s %p", __func__, drv);
-
- memset(&ggiodestroy, 0, sizeof(ggiodestroy));
- ggiodestroy.gctl_version = G_GATE_VERSION;
- ggiodestroy.gctl_unit = drv->unit;
- ggiodestroy.gctl_force = 1;
-
- // Remember errno.
- int rerrno = errno;
-
- int r = ioctl(drv->fd, G_GATE_CMD_DESTROY, &ggiodestroy);
- if (r == -1) {
- err("failed to destroy /dev/%s%d device", G_GATE_PROVIDER_NAME,
- drv->unit);
- }
- // Restore errno.
- errno = rerrno;
-
- free(drv);
-}
-
-int ggate_drv_resize(ggate_drv_t drv_, size_t newsize) {
- struct ggate_drv *drv = (struct ggate_drv *)drv_;
-
- debug(20, "%s %p: newsize=%zd", __func__, drv, newsize);
-
- struct g_gate_ctl_modify ggiomodify;
-
- memset(&ggiomodify, 0, sizeof(ggiomodify));
- ggiomodify.gctl_version = G_GATE_VERSION;
- ggiomodify.gctl_unit = drv->unit;
- ggiomodify.gctl_modify = GG_MODIFY_MEDIASIZE;
- ggiomodify.gctl_mediasize = newsize;
-
- int r = ioctl(drv->fd, G_GATE_CMD_MODIFY, &ggiomodify);
- if (r == -1) {
- r = -errno;
- err("failed to resize /dev/%s%d device", G_GATE_PROVIDER_NAME, drv->unit);
- }
- return r;
-}
-
-int ggate_drv_kill(const char *devname) {
- debug(20, "%s %s", __func__, devname);
-
- int fd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
- if (fd == -1) {
- err("failed to open /dev/" G_GATE_CTL_NAME);
- return -errno;
- }
-
- struct g_gate_ctl_destroy ggiodestroy;
- memset(&ggiodestroy, 0, sizeof(ggiodestroy));
- ggiodestroy.gctl_version = G_GATE_VERSION;
- ggiodestroy.gctl_unit = G_GATE_NAME_GIVEN;
- ggiodestroy.gctl_force = 1;
-
- strlcpy(ggiodestroy.gctl_name, devname, sizeof(ggiodestroy.gctl_name));
-
- int r = ioctl(fd, G_GATE_CMD_DESTROY, &ggiodestroy);
- if (r == -1) {
- r = -errno;
- err("failed to destroy %s device", devname);
- }
-
- close(fd);
- return r;
-}
-
-int ggate_drv_recv(ggate_drv_t drv_, ggate_drv_req_t *req) {
- struct ggate_drv *drv = (struct ggate_drv *)drv_;
- struct g_gate_ctl_io *ggio;
- int error, r;
-
- debug(20, "%s", __func__);
-
- ggio = calloc(1, sizeof(*ggio));
- if (ggio == NULL) {
- return -ENOMEM;
- }
-
- ggio->gctl_version = G_GATE_VERSION;
- ggio->gctl_unit = drv->unit;
- ggio->gctl_data = malloc(MAXPHYS);
- ggio->gctl_length = MAXPHYS;
-
- debug(20, "%s: waiting for request from kernel", __func__);
- if (ioctl(drv->fd, G_GATE_CMD_START, ggio) == -1) {
- err("%s: G_GATE_CMD_START failed", __func__);
- return -errno;
- }
-
- debug(20, "%s: got request from kernel: "
- "unit=%d, seq=%ju, cmd=%u, offset=%ju, length=%ju, error=%d, data=%p",
- __func__, ggio->gctl_unit, (uintmax_t)ggio->gctl_seq, ggio->gctl_cmd,
- (uintmax_t)ggio->gctl_offset, (uintmax_t)ggio->gctl_length,
- ggio->gctl_error, ggio->gctl_data);
-
- error = ggio->gctl_error;
- switch (error) {
- case 0:
- break;
- case ECANCELED:
- debug(10, "%s: canceled: exit gracefully", __func__);
- r = -error;
- goto fail;
- case ENOMEM:
- /*
- * Buffer too small? Impossible, we allocate MAXPHYS
- * bytes - request can't be bigger than that.
- */
- /* FALLTHROUGH */
- case ENXIO:
- default:
- errno = error;
- err("%s: G_GATE_CMD_START failed", __func__);
- r = -error;
- goto fail;
- }
-
- *req = ggio;
- return 0;
-
-fail:
- free(ggio->gctl_data);
- free(ggio);
- return r;
-}
-
-int ggate_drv_send(ggate_drv_t drv_, ggate_drv_req_t req) {
- struct ggate_drv *drv = (struct ggate_drv *)drv_;
- struct g_gate_ctl_io *ggio = (struct g_gate_ctl_io *)req;
- int r = 0;
-
- debug(20, "%s: send request to kernel: "
- "unit=%d, seq=%ju, cmd=%u, offset=%ju, length=%ju, error=%d, data=%p",
- __func__, ggio->gctl_unit, (uintmax_t)ggio->gctl_seq, ggio->gctl_cmd,
- (uintmax_t)ggio->gctl_offset, (uintmax_t)ggio->gctl_length,
- ggio->gctl_error, ggio->gctl_data);
-
- if (ioctl(drv->fd, G_GATE_CMD_DONE, ggio) == -1) {
- err("%s: G_GATE_CMD_DONE failed", __func__);
- r = -errno;
- }
-
- free(ggio->gctl_data);
- free(ggio);
- return r;
-}
-
-int ggate_drv_list(char **devs, size_t *size) {
- struct gmesh mesh;
- struct gclass *class;
- struct ggeom *gp;
- int r;
- size_t max_size;
-
- r = geom_gettree(&mesh);
- if (r != 0) {
- return -errno;
- }
-
- max_size = *size;
- *size = 0;
-
- LIST_FOREACH(class, &mesh.lg_class, lg_class) {
- if (strcmp(class->lg_name, G_GATE_CLASS_NAME) == 0) {
- LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
- (*size)++;
- }
- if (*size > max_size) {
- r = -ERANGE;
- goto done;
- }
- LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
- *devs = strdup(gp->lg_name);
- devs++;
- }
- }
- }
-
-done:
- geom_deletetree(&mesh);
- return r;
-}
-
-void ggate_drv_list_free(char **devs, size_t size) {
- size_t i;
-
- for (i = 0; i < size; i++) {
- free(devs[i]);
- }
-}