diff options
author | phk <phk@FreeBSD.org> | 2003-03-27 14:35:00 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2003-03-27 14:35:00 +0000 |
commit | 2d56ed957aaef6ee5d66bcc7c86d7832b4658de5 (patch) | |
tree | 84b36ca01e05be70dbdac8a6aee81afa4b8f1eaf /sys/geom | |
parent | 5447a01760d39222ce6958c12e893d7f8188883c (diff) | |
download | FreeBSD-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.h | 9 | ||||
-rw-r--r-- | sys/geom/geom_ctl.c | 308 | ||||
-rw-r--r-- | sys/geom/geom_ctl.h | 56 | ||||
-rw-r--r-- | sys/geom/geom_ext.h | 18 |
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" |