summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-03-27 14:35:00 +0000
committerphk <phk@FreeBSD.org>2003-03-27 14:35:00 +0000
commit2d56ed957aaef6ee5d66bcc7c86d7832b4658de5 (patch)
tree84b36ca01e05be70dbdac8a6aee81afa4b8f1eaf
parent5447a01760d39222ce6958c12e893d7f8188883c (diff)
downloadFreeBSD-src-2d56ed957aaef6ee5d66bcc7c86d7832b4658de5.zip
FreeBSD-src-2d56ed957aaef6ee5d66bcc7c86d7832b4658de5.tar.gz
Run a revision on the OAM api.
Use prefix gctl_ systematically. Add flag with access perms for each argument. Add ro/rw versions of argument building functions. General cleanup.
-rw-r--r--lib/libgeom/geom_ctl.c205
-rw-r--r--lib/libgeom/libgeom.h24
-rw-r--r--sys/geom/geom.h9
-rw-r--r--sys/geom/geom_ctl.c308
-rw-r--r--sys/geom/geom_ctl.h56
-rw-r--r--sys/geom/geom_ext.h18
6 files changed, 440 insertions, 180 deletions
diff --git a/lib/libgeom/geom_ctl.c b/lib/libgeom/geom_ctl.c
index 382d75a..e28c91f 100644
--- a/lib/libgeom/geom_ctl.c
+++ b/lib/libgeom/geom_ctl.c
@@ -35,29 +35,30 @@
#include <stdint.h>
#include <sys/types.h>
#include <stdarg.h>
+#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <paths.h>
#include <sys/queue.h>
-#define GEOM_CTL_TABLE 1
+#define GCTL_TABLE 1
#include <libgeom.h>
#include <geom/geom_ext.h>
void
-geom_ctl_dump(struct geom_ctl_req *req, FILE *f)
+gctl_dump(struct gctl_req *req, FILE *f)
{
u_int i;
int j;
- struct geom_ctl_req_arg *ap;
+ struct gctl_req_arg *ap;
if (req == NULL) {
- fprintf(f, "Dump of geom_ctl request at NULL\n");
+ fprintf(f, "Dump of gctl request at NULL\n");
return;
}
- fprintf(f, "Dump of geom_ctl %s request at %p:\n", req->reqt->name, req);
+ fprintf(f, "Dump of gctl %s request at %p:\n", req->reqt->name, req);
if (req->error != NULL)
fprintf(f, " error:\t\"%s\"\n", req->error);
else
@@ -68,24 +69,30 @@ geom_ctl_dump(struct geom_ctl_req *req, FILE *f)
fprintf(f, " param:\t\"%s\"", ap->name);
else
fprintf(f, " meta:\t@%jd", (intmax_t)ap->offset);
+ fprintf(f, " [%s%s",
+ ap->flag & GCTL_PARAM_RD ? "R" : "",
+ ap->flag & GCTL_PARAM_WR ? "W" : "");
fflush(f);
- if (ap->len < 0)
- fprintf(f, " = [%d] \"%s\"", -ap->len, (char *)ap->value);
+ if (ap->flag & GCTL_PARAM_ASCII)
+ fprintf(f, "%d] = \"%s\"", ap->len, (char *)ap->value);
else if (ap->len > 0) {
- fprintf(f, " = [%d]", ap->len);
+ fprintf(f, "%d] = ", ap->len);
fflush(f);
for (j = 0; j < ap->len; j++) {
fprintf(f, " %02x", ((u_char *)ap->value)[j]);
}
} else {
- fprintf(f, " = [0] %p", ap->value);
+ fprintf(f, "0] = %p", ap->value);
}
fprintf(f, "\n");
}
}
+/*
+ * Set an error message, if one does not already exist.
+ */
static void
-geom_ctl_set_error(struct geom_ctl_req *req, const char *error, ...)
+gctl_set_error(struct gctl_req *req, const char *error, ...)
{
va_list ap;
@@ -93,107 +100,145 @@ geom_ctl_set_error(struct geom_ctl_req *req, const char *error, ...)
return;
va_start(ap, error);
vasprintf(&req->error, error, ap);
+ va_end(ap);
}
+/*
+ * Check that a malloc operation succeeded, and set a consistent error
+ * message if not.
+ */
static void
-geom_ctl_check_alloc(struct geom_ctl_req *req, void *ptr)
+gctl_check_alloc(struct gctl_req *req, void *ptr)
{
if (ptr != NULL)
return;
- geom_ctl_set_error(req, "Could not allocate memory");
+ gctl_set_error(req, "Could not allocate memory");
+ if (req->error == NULL)
+ req->error = "Could not allocate memory";
}
-struct geom_ctl_req *
-geom_ctl_get_handle(enum geom_ctl_request req)
+/*
+ * Allocate a new request handle of the specified type.
+ * XXX: Why bother checking the type ?
+ */
+struct gctl_req *
+gctl_get_handle(enum gctl_request req)
{
- struct geom_ctl_req_table *gtp;
- struct geom_ctl_req *rp;
+ struct gctl_req_table *gtp;
+ struct gctl_req *rp;
rp = calloc(1, sizeof *rp);
if (rp == NULL)
return (NULL);
for (gtp = gcrt; gtp->request != req; gtp++)
- if (gtp->request == GEOM_INVALID_REQUEST)
+ if (gtp->request == GCTL_INVALID_REQUEST)
break;
rp->request = req;
rp->reqt = gtp;
- if (rp->reqt->request == GEOM_INVALID_REQUEST)
- geom_ctl_set_error(rp, "Invalid request");
+ if (rp->reqt->request == GCTL_INVALID_REQUEST)
+ gctl_set_error(rp, "Invalid request");
return (rp);
}
-void
-geom_ctl_set_param(struct geom_ctl_req *req, const char *name, int len, void* value)
+/*
+ * Allocate space for another argument.
+ */
+static struct gctl_req_arg *
+gctl_new_arg(struct gctl_req *req)
{
- struct geom_ctl_req_arg *ap;
+ struct gctl_req_arg *ap;
- if (req == NULL || req->error != NULL)
- return;
- if (req->reqt->params == 0)
- geom_ctl_set_error(req, "Request takes no parameters");
req->narg++;
req->arg = realloc(req->arg, sizeof *ap * req->narg);
- geom_ctl_check_alloc(req, req->arg);
- if (req->arg != NULL) {
- ap = req->arg + (req->narg - 1);
- memset(ap, 0, sizeof *ap);
- ap->name = strdup(name);
- geom_ctl_check_alloc(req, ap->name);
- ap->nlen = strlen(ap->name);
- ap->len = len;
- if (len > 0) {
- ap->value = value;
- } else if (len < 0) {
- ap->len = -strlen(value);
- ap->value = strdup(value);
- } else {
- ap->value = value;
- }
- if (len != 0)
- geom_ctl_check_alloc(req, ap->value);
- } else {
+ gctl_check_alloc(req, req->arg);
+ if (req->arg == NULL) {
req->narg = 0;
+ return (NULL);
}
+ ap = req->arg + (req->narg - 1);
+ memset(ap, 0, sizeof *ap);
+ return (ap);
}
void
-geom_ctl_set_meta(struct geom_ctl_req *req, off_t offset, u_int len, void* value)
+gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value)
{
- struct geom_ctl_req_arg *ap;
- u_int i;
+ struct gctl_req_arg *ap;
if (req == NULL || req->error != NULL)
return;
- if (req->reqt->meta == 0)
- geom_ctl_set_error(req, "Request takes no meta data");
- for (i = 0; i < req->narg; i++) {
- ap = &req->arg[i];
- if (ap->name != NULL)
- continue;
- if (ap->offset >= offset + len)
- continue;
- if (ap->offset + ap->len <= offset)
- continue;
- geom_ctl_set_error(req, "Overlapping meta data");
+ ap = gctl_new_arg(req);
+ if (ap == NULL)
return;
- }
- req->narg++;
- req->arg = realloc(req->arg, sizeof *ap * req->narg);
- geom_ctl_check_alloc(req, req->arg);
- if (req->arg != NULL) {
- ap = req->arg + (req->narg - 1);
- memset(ap, 0, sizeof *ap);
- ap->value = value;
- ap->offset = offset;
+ ap->name = strdup(name);
+ gctl_check_alloc(req, ap->name);
+ ap->nlen = strlen(ap->name) + 1;
+ ap->value = __DECONST(void *, value);
+ ap->flag = GCTL_PARAM_RD;
+ if (len >= 0)
ap->len = len;
- } else {
- req->narg = 0;
+ else if (len < 0) {
+ ap->flag |= GCTL_PARAM_ASCII;
+ ap->len = strlen(value) + 1;
}
}
+void
+gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value)
+{
+ struct gctl_req_arg *ap;
+
+ if (req == NULL || req->error != NULL)
+ return;
+ ap = gctl_new_arg(req);
+ if (ap == NULL)
+ return;
+ ap->name = strdup(name);
+ gctl_check_alloc(req, ap->name);
+ ap->nlen = strlen(ap->name) + 1;
+ ap->value = value;
+ ap->flag = GCTL_PARAM_RW;
+ if (len >= 0)
+ ap->len = len;
+ else if (len < 0)
+ ap->len = strlen(value) + 1;
+}
+
+void
+gctl_ro_meta(struct gctl_req *req, off_t offset, u_int len, const void* value)
+{
+ struct gctl_req_arg *ap;
+
+ if (req == NULL || req->error != NULL)
+ return;
+ ap = gctl_new_arg(req);
+ if (ap == NULL)
+ return;
+ ap->value = __DECONST(void *, value);
+ ap->flag = GCTL_PARAM_RD;
+ ap->offset = offset;
+ ap->len = len;
+}
+
+void
+gctl_rw_meta(struct gctl_req *req, off_t offset, u_int len, void* value)
+{
+ struct gctl_req_arg *ap;
+
+ if (req == NULL || req->error != NULL)
+ return;
+ ap = gctl_new_arg(req);
+ if (ap == NULL)
+ return;
+ ap->value = value;
+ ap->flag = GCTL_PARAM_RW;
+ ap->offset = offset;
+ ap->len = len;
+}
+
const char *
-geom_ctl_issue(struct geom_ctl_req *req)
+gctl_issue(struct gctl_req *req)
{
int fd, error;
@@ -202,16 +247,21 @@ geom_ctl_issue(struct geom_ctl_req *req)
if (req->error != NULL)
return (req->error);
- req->version = GEOM_CTL_VERSION;
+ req->version = GCTL_VERSION;
req->lerror = BUFSIZ; /* XXX: arbitrary number */
req->error = malloc(req->lerror);
+ if (req->error == NULL) {
+ gctl_check_alloc(req, req->error);
+ return (req->error);
+ }
memset(req->error, 0, req->lerror);
req->lerror--;
fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY);
if (fd < 0)
return(strerror(errno));
error = ioctl(fd, GEOM_CTL, req);
- if (error && errno == EINVAL && req->error[0] != '\0')
+ close(fd);
+ if (req->error[0] != '\0')
return (req->error);
if (error != 0)
return(strerror(errno));
@@ -219,19 +269,18 @@ geom_ctl_issue(struct geom_ctl_req *req)
}
void
-geom_ctl_free(struct geom_ctl_req *req)
+gctl_free(struct gctl_req *req)
{
u_int i;
+ if (req == NULL)
+ return;
for (i = 0; i < req->narg; i++) {
if (req->arg[i].name != NULL)
free(req->arg[i].name);
- if (req->arg[i].len < 0)
- free(req->arg[i].value);
}
+ free(req->arg);
if (req->error != NULL)
free(req->error);
- free(req->arg);
free(req);
}
-
diff --git a/lib/libgeom/libgeom.h b/lib/libgeom/libgeom.h
index 9f00253..8b1c2e8 100644
--- a/lib/libgeom/libgeom.h
+++ b/lib/libgeom/libgeom.h
@@ -129,23 +129,17 @@ void geom_deletetree(struct gmesh *gmp);
/* geom_ctl.c */
-struct geom_ctl_req;
+struct gctl_req;
#ifdef _STDIO_H_ /* limit #include pollution */
-void geom_ctl_dump(struct geom_ctl_req *req, FILE *f);
+void gctl_dump(struct gctl_req *req, FILE *f);
#endif
-void geom_ctl_free(struct geom_ctl_req *req);
-struct geom_ctl_req *geom_ctl_get_handle(enum geom_ctl_request req);
-const char *geom_ctl_issue(struct geom_ctl_req *req);
-void geom_ctl_set_class_by_id(struct geom_ctl_req *req, void *id);
-void geom_ctl_set_class_by_name(struct geom_ctl_req *req, const char *name);
-void geom_ctl_set_consumer_by_id(struct geom_ctl_req *req, void *id);
-void geom_ctl_set_consumer_by_name(struct geom_ctl_req *req, const char *name);
-void geom_ctl_set_geom_by_id(struct geom_ctl_req *req, void *id);
-void geom_ctl_set_geom_by_name(struct geom_ctl_req *req, const char *name);
-void geom_ctl_set_meta(struct geom_ctl_req *req, off_t offset, u_int len, void* val);
-void geom_ctl_set_param(struct geom_ctl_req *req, const char *name, int len, void* val);
-void geom_ctl_set_provider_by_id(struct geom_ctl_req *req, void *id);
-void geom_ctl_set_provider_by_name(struct geom_ctl_req *req, const char *name);
+void gctl_free(struct gctl_req *req);
+struct gctl_req *gctl_get_handle(enum gctl_request req);
+const char *gctl_issue(struct gctl_req *req);
+void gctl_ro_meta(struct gctl_req *req, off_t offset, u_int len, const void* val);
+void gctl_rw_meta(struct gctl_req *req, off_t offset, u_int len, void* val);
+void gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* val);
+void gctl_rw_param(struct gctl_req *req, const char *name, int len, void* val);
#endif /* _LIBGEOM_H_ */
diff --git a/sys/geom/geom.h b/sys/geom/geom.h
index f07485a..811fb8c 100644
--- a/sys/geom/geom.h
+++ b/sys/geom/geom.h
@@ -62,9 +62,12 @@ struct g_stat;
struct thread;
struct bio;
struct sbuf;
+struct gctl_req;
struct g_configargs;
typedef int g_config_t (struct g_configargs *ca);
+typedef int g_ctl_create_geom_t (struct gctl_req *, struct g_class *cp, struct g_provider *pp);
+typedef int g_ctl_destroy_geom_t (struct gctl_req *, struct g_class *cp, struct g_geom *gp);
typedef struct g_geom * g_taste_t (struct g_class *, struct g_provider *,
int flags);
#define G_TF_NORMAL 0
@@ -90,6 +93,8 @@ struct g_class {
const char *name;
g_taste_t *taste;
g_config_t *config;
+ g_ctl_create_geom_t *create_geom;
+ g_ctl_destroy_geom_t *destroy_geom;
/*
* The remaning elements are private and classes should use
* the G_CLASS_INITIALIZER macro to initialize them.
@@ -426,6 +431,10 @@ struct gcfg_magicrw {
*/
+/* geom_ctl.c */
+void *gctl_get_param(struct gctl_req *req, const char *param, int *len);
+int gctl_error(struct gctl_req *req, const char *errtxt);
+
/* geom_enc.c */
uint16_t g_dec_be2(const u_char *p);
uint32_t g_dec_be4(const u_char *p);
diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c
index eda91d5..e098c18 100644
--- a/sys/geom/geom_ctl.c
+++ b/sys/geom/geom_ctl.c
@@ -55,7 +55,7 @@
#include <geom/geom.h>
#include <geom/geom_int.h>
-#define GEOM_CTL_TABLE 1
+#define GCTL_TABLE 1
#include <geom/geom_ctl.h>
#include <geom/geom_ext.h>
@@ -74,6 +74,10 @@ g_ctl_init(void)
make_dev(&g_ctl_cdevsw, 0,
UID_ROOT, GID_OPERATOR, 0640, PATH_GEOM_CTL);
+ KASSERT(GCTL_PARAM_RD == VM_PROT_READ,
+ ("GCTL_PARAM_RD != VM_PROT_READ"));
+ KASSERT(GCTL_PARAM_WR == VM_PROT_WRITE,
+ ("GCTL_PARAM_WR != VM_PROT_WRITE"));
}
static int
@@ -125,8 +129,8 @@ g_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct th
* XXX: should not be static.
* XXX: should take printf like args.
*/
-static int
-g_ctl_seterror(struct geom_ctl_req *req, const char *errtxt)
+int
+gctl_error(struct gctl_req *req, const char *errtxt)
{
int error;
@@ -142,7 +146,7 @@ g_ctl_seterror(struct geom_ctl_req *req, const char *errtxt)
* XXX: this should really be a standard function in the kernel.
*/
static void *
-geom_alloc_copyin(void *uaddr, size_t len, int *errp)
+geom_alloc_copyin(struct gctl_req *req, void *uaddr, size_t len, int *errp)
{
int error;
void *ptr;
@@ -154,6 +158,7 @@ geom_alloc_copyin(void *uaddr, size_t len, int *errp)
error = copyin(uaddr, ptr, len);
if (!error)
return (ptr);
+ gctl_error(req, "no access to argument");
*errp = error;
if (ptr != NULL)
g_free(ptr);
@@ -169,45 +174,46 @@ geom_alloc_copyin(void *uaddr, size_t len, int *errp)
*/
static int
-geom_ctl_copyin(struct geom_ctl_req *req)
+gctl_copyin(struct gctl_req *req)
{
int error, i, j;
- struct geom_ctl_req_arg *ap;
+ struct gctl_req_arg *ap;
char *p;
error = 0;
- if (!useracc(req->error, req->lerror, VM_PROT_WRITE))
- return (g_ctl_seterror(req, "No access to error field"));
- ap = geom_alloc_copyin(req->arg, req->narg * sizeof(*ap), &error);
- if (ap == NULL)
+ ap = geom_alloc_copyin(req, req->arg, req->narg * sizeof(*ap), &error);
+ if (ap == NULL) {
+ gctl_error(req, "copyin() of arguments failed");
return (error);
+ }
+
for (i = 0; !error && i < req->narg; i++) {
- if (ap[i].len < 0 &&
- !useracc(ap[i].value, 1 + -ap[i].len, VM_PROT_READ))
- error = g_ctl_seterror(req, "No access to param data");
- else if (ap[i].len > 0 &&
- !useracc(ap[i].value, ap[i].len,
- VM_PROT_READ | VM_PROT_WRITE))
- error = g_ctl_seterror(req, "No access to param data");
- if (ap[i].name == NULL)
- continue;
+ if (ap[i].len > 0 &&
+ !useracc(ap[i].value, ap[i].len,
+ ap[i].flag & GCTL_PARAM_RW))
+ error = gctl_error(req, "no access to param data");
+ if (ap[i].name == NULL) {
+ if (req->reqt->meta)
+ continue;
+ error = gctl_error(req,
+ "request does not take metadata arguments");
+ break;
+ }
p = NULL;
- if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN)
- error = EINVAL;
- if (error)
+ if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) {
+ error = gctl_error(req, "wrong param name length");
break;
- p = geom_alloc_copyin(ap[i].name, ap[i].nlen + 1, &error);
- if (error)
+ }
+ p = geom_alloc_copyin(req, ap[i].name, ap[i].nlen, &error);
+ if (p == NULL)
break;
- if (p[ap[i].nlen] != '\0')
- error = EINVAL;
- if (!error) {
- ap[i].name = p;
- ap[i].nlen = 0;
- } else {
+ if (p[ap[i].nlen - 1] != '\0') {
+ error = gctl_error(req, "unterminated param name");
g_free(p);
break;
}
+ ap[i].name = p;
+ ap[i].nlen = 0;
}
if (!error) {
req->arg = ap;
@@ -221,17 +227,17 @@ geom_ctl_copyin(struct geom_ctl_req *req)
}
static void
-geom_ctl_dump(struct geom_ctl_req *req)
+gctl_dump(struct gctl_req *req)
{
u_int i;
int j, error;
- struct geom_ctl_req_arg *ap;
+ struct gctl_req_arg *ap;
void *p;
- printf("Dump of geom_ctl %s request at %p:\n", req->reqt->name, req);
+ printf("Dump of gctl %s request at %p:\n", req->reqt->name, req);
if (req->lerror > 0) {
- p = geom_alloc_copyin(req->error, req->lerror, &error);
+ p = geom_alloc_copyin(req, req->error, req->lerror, &error);
if (p != NULL) {
((char *)p)[req->lerror - 1] = '\0';
printf(" error:\t\"%s\"\n", (char *)p);
@@ -244,15 +250,19 @@ geom_ctl_dump(struct geom_ctl_req *req)
printf(" param:\t\"%s\"", ap->name);
else
printf(" meta:\t@%jd", (intmax_t)ap->offset);
- printf(" [%d] = ", ap->len);
- if (ap->len < 0) {
- p = geom_alloc_copyin(ap->value, 1 + -ap->len, &error);
- ((char *)p)[-ap->len] = '\0';
- if (p != NULL)
+ printf(" [%s%s%d] = ",
+ ap->flag & GCTL_PARAM_RD ? "R" : "",
+ ap->flag & GCTL_PARAM_WR ? "W" : "",
+ ap->len);
+ if (ap->flag & GCTL_PARAM_ASCII) {
+ p = geom_alloc_copyin(req, ap->value, ap->len, &error);
+ if (p != NULL) {
+ ((char *)p)[ap->len - 1] = '\0';
printf("\"%s\"", (char *)p);
+ }
g_free(p);
} else if (ap->len > 0) {
- p = geom_alloc_copyin(ap->value, ap->len, &error);
+ p = geom_alloc_copyin(req, ap->value, ap->len, &error);
for (j = 0; j < ap->len; j++)
printf(" %02x", ((u_char *)p)[j]);
g_free(p);
@@ -263,6 +273,171 @@ geom_ctl_dump(struct geom_ctl_req *req)
}
}
+void *
+gctl_get_param(struct gctl_req *req, const char *param, int *len)
+{
+ int i, error, j;
+ void *p;
+ struct gctl_req_arg *ap;
+
+ for (i = 0; i < req->narg; i++) {
+ ap = &req->arg[i];
+ if (strcmp(param, ap->name))
+ continue;
+ if (!(ap->flag & GCTL_PARAM_RD))
+ continue;
+ if (ap->len > 0)
+ j = ap->len;
+ else
+ j = 0;
+ if (j != 0)
+ p = geom_alloc_copyin(req, ap->value, j, &error);
+ /* XXX: should not fail, tested prviously */
+ else
+ p = ap->value;
+ if (len != NULL)
+ *len = j;
+ return (p);
+ }
+ return (NULL);
+}
+
+static struct g_class*
+gctl_get_class(struct gctl_req *req)
+{
+ char *p;
+ int len;
+ struct g_class *cp;
+
+ p = gctl_get_param(req, "class", &len);
+ if (p == NULL)
+ return (NULL);
+ if (p[len - 1] != '\0') {
+ gctl_error(req, "Unterminated class name");
+ g_free(p);
+ return (NULL);
+ }
+ LIST_FOREACH(cp, &g_classes, class) {
+ if (!strcmp(p, cp->name)) {
+ g_free(p);
+ return (cp);
+ }
+ }
+ gctl_error(req, "Class not found");
+ return (NULL);
+}
+
+static struct g_geom*
+gctl_get_geom(struct gctl_req *req, struct g_class *mpr)
+{
+ char *p;
+ int len;
+ struct g_class *mp;
+ struct g_geom *gp;
+
+ p = gctl_get_param(req, "geom", &len);
+ if (p == NULL)
+ return (NULL);
+ if (p[len - 1] != '\0') {
+ gctl_error(req, "Unterminated provider name");
+ g_free(p);
+ return (NULL);
+ }
+ LIST_FOREACH(mp, &g_classes, class) {
+ if (mpr != NULL && mpr != mp)
+ continue;
+ LIST_FOREACH(gp, &mp->geom, geom) {
+ if (!strcmp(p, gp->name)) {
+ g_free(p);
+ return (gp);
+ }
+ }
+ }
+ gctl_error(req, "Geom not found");
+ return (NULL);
+}
+
+static struct g_provider*
+gctl_get_provider(struct gctl_req *req)
+{
+ char *p;
+ int len;
+ struct g_class *cp;
+ struct g_geom *gp;
+ struct g_provider *pp;
+
+ p = gctl_get_param(req, "provider", &len);
+ if (p == NULL)
+ return (NULL);
+ if (p[len - 1] != '\0') {
+ gctl_error(req, "Unterminated provider name");
+ g_free(p);
+ return (NULL);
+ }
+ LIST_FOREACH(cp, &g_classes, class) {
+ LIST_FOREACH(gp, &cp->geom, geom) {
+ LIST_FOREACH(pp, &gp->provider, provider) {
+ if (!strcmp(p, pp->name)) {
+ g_free(p);
+ return (pp);
+ }
+ }
+ }
+ }
+ gctl_error(req, "Provider not found");
+ return (NULL);
+}
+
+static void
+gctl_create_geom(struct gctl_req *req)
+{
+ struct g_class *mp;
+ struct g_provider *pp;
+
+ g_topology_assert();
+ mp = gctl_get_class(req);
+ if (mp == NULL)
+ return;
+ printf("Found class: %p\n", mp);
+ if (mp->create_geom == NULL) {
+ gctl_error(req, "Class has no create_geom method");
+ return;
+ }
+ pp = gctl_get_provider(req);
+ printf("Found provider: %p\n", pp);
+ mp->create_geom(req, mp, pp);
+ g_topology_assert();
+}
+
+static void
+gctl_destroy_geom(struct gctl_req *req)
+{
+ struct g_class *mp;
+ struct g_geom *gp;
+
+ g_topology_assert();
+ mp = gctl_get_class(req);
+ if (mp == NULL)
+ return;
+ printf("Found class: %p\n", mp);
+ if (mp->destroy_geom == NULL) {
+ gctl_error(req, "Class has no destroy_geom method");
+ return;
+ }
+ gp = gctl_get_geom(req, mp);
+ if (gp == NULL) {
+ gctl_error(req, "Geom not specified");
+ return;
+ }
+ if (gp->class != mp) {
+ gctl_error(req, "Geom not of specificed class");
+ return;
+ }
+ printf("Found geom: %p\n", gp);
+ mp->destroy_geom(req, mp, gp);
+ g_topology_assert();
+}
+
/*
* Handle ioctl from libgeom::geom_ctl.c
*/
@@ -271,28 +446,53 @@ g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *t
{
int error;
int i;
- struct geom_ctl_req *req;
+ struct gctl_req *req;
req = (void *)data;
+ /* It is an error if we cannot return an error text */
if (req->lerror < 1)
return (EINVAL);
- if (req->version != GEOM_CTL_VERSION)
- return (g_ctl_seterror(req,
- "Kernel and libgeom version skew."));
- for (i = 0; gcrt[i].request != GEOM_INVALID_REQUEST; i++)
- if (gcrt[i].request == req->request) {
- req->reqt = &gcrt[i];
+ if (!useracc(req->error, req->lerror, VM_PROT_WRITE))
+ return (EINVAL);
+
+ /* Check the version */
+ if (req->version != GCTL_VERSION)
+ return (gctl_error(req,
+ "kernel and libgeom version mismatch."));
+
+ /* Check the request type */
+ for (i = 0; gcrt[i].request != GCTL_INVALID_REQUEST; i++)
+ if (gcrt[i].request == req->request)
break;
- }
- if (gcrt[i].request == GEOM_INVALID_REQUEST)
- return (g_ctl_seterror(req, "Invalid request"));
- error = geom_ctl_copyin(req);
+ if (gcrt[i].request == GCTL_INVALID_REQUEST)
+ return (gctl_error(req, "invalid request"));
+ req->reqt = &gcrt[i];
+
+ /* Get things on board */
+ error = gctl_copyin(req);
if (error)
return (error);
- req->reqt = &gcrt[i];
+
+ gctl_dump(req);
+#if 0
g_stall_events();
- geom_ctl_dump(req);
+#endif
+ g_topology_lock();
+ switch (req->request) {
+ case GCTL_CREATE_GEOM:
+ gctl_create_geom(req);
+ break;
+ case GCTL_DESTROY_GEOM:
+ gctl_destroy_geom(req);
+ break;
+ default:
+ gctl_error(req, "XXX: TBD");
+ break;
+ }
+ g_topology_unlock();
+#if 0
g_release_events();
+#endif
return (0);
}
@@ -310,7 +510,9 @@ g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
PICKUP_GIANT();
break;
case GEOM_CTL:
+ DROP_GIANT();
error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td);
+ PICKUP_GIANT();
break;
default:
error = ENOTTY;
diff --git a/sys/geom/geom_ctl.h b/sys/geom/geom_ctl.h
index 240a48a..15bcef1 100644
--- a/sys/geom/geom_ctl.h
+++ b/sys/geom/geom_ctl.h
@@ -35,27 +35,27 @@
/*
* Version number. Used to check consistency between kernel and libgeom.
*/
-#define GEOM_CTL_VERSION 1
+#define GCTL_VERSION 1
/*
* Primitives.
*/
-enum geom_ctl_request {
- GEOM_INVALID_REQUEST = 0,
- GEOM_CREATE_GEOM,
- GEOM_NEW_GEOM,
- GEOM_ATTACH,
- GEOM_DETACH,
- GEOM_CREATE_PROVIDER,
- GEOM_DESTROY_PROVIDER,
- GEOM_INSERT_GEOM,
- GEOM_ELIMINATE_GEOM,
- GEOM_WRITE_META,
- GEOM_READ_META
+enum gctl_request {
+ GCTL_INVALID_REQUEST = 0,
+ GCTL_CREATE_GEOM,
+ GCTL_DESTROY_GEOM,
+ GCTL_ATTACH,
+ GCTL_DETACH,
+ GCTL_CREATE_PROVIDER,
+ GCTL_DESTROY_PROVIDER,
+ GCTL_INSERT_GEOM,
+ GCTL_ELIMINATE_GEOM,
+ GCTL_WRITE_META,
+ GCTL_READ_META
};
-#ifdef GEOM_CTL_TABLE
-struct geom_ctl_req_table {
+#ifdef GCTL_TABLE
+struct gctl_req_table {
int class;
int geom;
int provider;
@@ -63,24 +63,24 @@ struct geom_ctl_req_table {
int params;
int meta;
char *name;
- enum geom_ctl_request request;
+ enum gctl_request request;
} gcrt[] = {
/* Cl Ge Pr Co Pa Me Name Request */
- { 1, 1, 1, 0, 1, 0, "create geom", GEOM_CREATE_GEOM },
- { 1, 1, 0, 0, 1, 0, "new geom", GEOM_NEW_GEOM },
- { 0, 1, 1, 0, 1, 0, "attach", GEOM_ATTACH },
- { 0, 1, 1, 0, 1, 0, "detach", GEOM_DETACH },
- { 0, 1, 0, 0, 1, 0, "create provider", GEOM_CREATE_PROVIDER },
- { 0, 1, 1, 0, 1, 0, "destroy provider", GEOM_DESTROY_PROVIDER },
- { 1, 1, 1, 0, 1, 0, "insert geom", GEOM_INSERT_GEOM },
- { 0, 1, 0, 0, 1, 0, "eliminate geom", GEOM_ELIMINATE_GEOM },
- { 0, 1, 0, 0, 1, 1, "write meta", GEOM_WRITE_META },
- { 0, 1, 0, 0, 1, 1, "read meta", GEOM_READ_META },
+ { 1, 0, 1, 0, 1, 0, "create geom", GCTL_CREATE_GEOM },
+ { 0, 1, 0, 0, 1, 0, "destroy geom", GCTL_DESTROY_GEOM },
+ { 0, 1, 1, 0, 1, 0, "attach", GCTL_ATTACH },
+ { 0, 1, 1, 0, 1, 0, "detach", GCTL_DETACH },
+ { 0, 1, 0, 0, 1, 0, "create provider", GCTL_CREATE_PROVIDER },
+ { 0, 1, 1, 0, 1, 0, "destroy provider", GCTL_DESTROY_PROVIDER },
+ { 1, 1, 1, 0, 1, 0, "insert geom", GCTL_INSERT_GEOM },
+ { 0, 1, 0, 0, 1, 0, "eliminate geom", GCTL_ELIMINATE_GEOM },
+ { 0, 1, 0, 0, 1, 1, "write meta", GCTL_WRITE_META },
+ { 0, 1, 0, 0, 1, 1, "read meta", GCTL_READ_META },
/* Terminator entry */
- { 1, 1, 1, 1, 1, 1, "*INVALID*", GEOM_INVALID_REQUEST }
+ { 1, 1, 1, 1, 1, 1, "*INVALID*", GCTL_INVALID_REQUEST }
};
-#endif /* GEOM_CTL_TABLE */
+#endif /* GCTL_TABLE */
#endif /* _GEOM_GEOM_CTL_H_ */
diff --git a/sys/geom/geom_ext.h b/sys/geom/geom_ext.h
index 8cc795c..a48fc0b 100644
--- a/sys/geom/geom_ext.h
+++ b/sys/geom/geom_ext.h
@@ -40,26 +40,32 @@
#include <sys/ioccom.h>
#include <geom/geom_ctl.h>
-struct geom_ctl_req_arg {
+struct gctl_req_arg {
u_int nlen;
char *name;
off_t offset;
+ int flag;
int len;
void *value;
};
-struct geom_ctl_req {
+#define GCTL_PARAM_RD 1 /* Must match VM_PROT_READ */
+#define GCTL_PARAM_WR 2 /* Must match VM_PROT_WRITE */
+#define GCTL_PARAM_RW (GCTL_PARAM_RD | GCTL_PARAM_WR)
+#define GCTL_PARAM_ASCII 4
+
+struct gctl_req {
u_int version;
u_int serial;
- enum geom_ctl_request request;
+ enum gctl_request request;
u_int narg;
- struct geom_ctl_req_arg *arg;
+ struct gctl_req_arg *arg;
u_int lerror;
char *error;
- struct geom_ctl_req_table *reqt;
+ struct gctl_req_table *reqt;
};
-#define GEOM_CTL _IOW('G', GEOM_CTL_VERSION, struct geom_ctl_req)
+#define GEOM_CTL _IOW('G', GCTL_VERSION, struct gctl_req)
#define PATH_GEOM_CTL "geom.ctl"
OpenPOWER on IntegriCloud