summaryrefslogtreecommitdiffstats
path: root/sys/geom
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 /sys/geom
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.
Diffstat (limited to 'sys/geom')
-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
4 files changed, 304 insertions, 87 deletions
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