diff options
-rw-r--r-- | sbin/bsdlabel/bsdlabel.c | 12 | ||||
-rw-r--r-- | sbin/gbde/gbde.c | 6 | ||||
-rw-r--r-- | sbin/sunlabel/sunlabel.c | 8 | ||||
-rw-r--r-- | sys/geom/bde/g_bde.c | 58 | ||||
-rw-r--r-- | sys/geom/geom.h | 10 | ||||
-rw-r--r-- | sys/geom/geom_bsd.c | 36 | ||||
-rw-r--r-- | sys/geom/geom_ctl.c | 438 | ||||
-rw-r--r-- | sys/geom/geom_ctl.h | 74 | ||||
-rw-r--r-- | sys/geom/geom_ext.h | 72 | ||||
-rw-r--r-- | sys/geom/geom_sunlabel.c | 33 |
10 files changed, 303 insertions, 444 deletions
diff --git a/sbin/bsdlabel/bsdlabel.c b/sbin/bsdlabel/bsdlabel.c index a0e3cdb..31e57b7 100644 --- a/sbin/bsdlabel/bsdlabel.c +++ b/sbin/bsdlabel/bsdlabel.c @@ -359,10 +359,10 @@ writelabel(void) fd = open(specname, O_RDWR); if (fd < 0) { - grq = gctl_get_handle(GCTL_CONFIG_GEOM); + grq = gctl_get_handle(); + gctl_ro_param(grq, "verb", -1, "write label"); gctl_ro_param(grq, "class", -1, "BSD"); gctl_ro_param(grq, "geom", -1, dkname); - gctl_ro_param(grq, "verb", -1, "write label"); gctl_ro_param(grq, "label", 148+16*8, bootarea + labeloffset); errstr = gctl_issue(grq); if (errstr != NULL) { @@ -372,10 +372,10 @@ writelabel(void) } gctl_free(grq); if (installboot) { - grq = gctl_get_handle(GCTL_CONFIG_GEOM); + grq = gctl_get_handle(); + gctl_ro_param(grq, "verb", -1, "write bootcode"); gctl_ro_param(grq, "class", -1, "BSD"); gctl_ro_param(grq, "geom", -1, dkname); - gctl_ro_param(grq, "verb", -1, "write bootcode"); gctl_ro_param(grq, "bootcode", BBSIZE, bootarea); errstr = gctl_issue(grq); if (errstr != NULL) { @@ -419,10 +419,10 @@ readlabel(int flag) if (flag && error) errx(1, "%s: no valid label found", specname); - grq = gctl_get_handle(GCTL_CONFIG_GEOM); + grq = gctl_get_handle(); + gctl_ro_param(grq, "verb", -1, "read mbroffset"); gctl_ro_param(grq, "class", -1, "BSD"); gctl_ro_param(grq, "geom", -1, dkname); - gctl_ro_param(grq, "verb", -1, "read mbroffset"); gctl_rw_param(grq, "mbroffset", sizeof(mbroffset), &mbroffset); errstr = gctl_issue(grq); if (errstr != NULL) { diff --git a/sbin/gbde/gbde.c b/sbin/gbde/gbde.c index f36df05..1b1c2c3 100644 --- a/sbin/gbde/gbde.c +++ b/sbin/gbde/gbde.c @@ -225,7 +225,8 @@ cmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile) struct gctl_req *r; const char *errstr; - r = gctl_get_handle(GCTL_CREATE_GEOM); + r = gctl_get_handle(); + gctl_ro_param(r, "verb", -1, "create geom"); gctl_ro_param(r, "class", -1, "BDE"); gctl_ro_param(r, "provider", -1, dest); gctl_ro_param(r, "pass", SHA512_DIGEST_LENGTH, sc->sha2); @@ -252,7 +253,8 @@ cmd_detach(const char *dest) const char *errstr; char buf[BUFSIZ]; - r = gctl_get_handle(GCTL_DESTROY_GEOM); + r = gctl_get_handle(); + gctl_ro_param(r, "verb", -1, "destroy geom"); gctl_ro_param(r, "class", -1, "BDE"); sprintf(buf, "%s.bde", dest); gctl_ro_param(r, "geom", -1, buf); diff --git a/sbin/sunlabel/sunlabel.c b/sbin/sunlabel/sunlabel.c index 08e6745..1de2562 100644 --- a/sbin/sunlabel/sunlabel.c +++ b/sbin/sunlabel/sunlabel.c @@ -352,20 +352,20 @@ write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); fd = open(path, O_RDWR); if (fd < 0) { - grq = gctl_get_handle(GCTL_CONFIG_GEOM); + grq = gctl_get_handle(); + gctl_ro_param(grq, "verb", -1, "write label"); gctl_ro_param(grq, "class", -1, "SUN"); gctl_ro_param(grq, "geom", -1, disk); - gctl_ro_param(grq, "verb", -1, "write label"); gctl_ro_param(grq, "label", sizeof buf, buf); errstr = gctl_issue(grq); if (errstr != NULL) errx(1, "%s", errstr); gctl_free(grq); if (Bflag) { - grq = gctl_get_handle(GCTL_CONFIG_GEOM); + grq = gctl_get_handle(); + gctl_ro_param(grq, "verb", -1, "write bootcode"); gctl_ro_param(grq, "class", -1, "SUN"); gctl_ro_param(grq, "geom", -1, disk); - gctl_ro_param(grq, "verb", -1, "write bootcode"); gctl_ro_param(grq, "bootcode", sizeof boot, boot); errstr = gctl_issue(grq); if (errstr != NULL) diff --git a/sys/geom/bde/g_bde.c b/sys/geom/bde/g_bde.c index 5e10ba3..e3e06ec 100644 --- a/sys/geom/bde/g_bde.c +++ b/sys/geom/bde/g_bde.c @@ -111,7 +111,7 @@ g_bde_access(struct g_provider *pp, int dr, int dw, int de) return (g_access_rel(cp, dr, dw, de)); } -static int +static void g_bde_create_geom(struct gctl_req *req, struct g_class *mp, struct g_provider *pp) { struct g_geom *gp; @@ -124,8 +124,6 @@ g_bde_create_geom(struct gctl_req *req, struct g_class *mp, struct g_provider *p void *pass; void *key; - if (pp == NULL) - return (gctl_error(req, "Provider needed")); g_trace(G_T_TOPOLOGY, "g_bde_create_geom(%s, %s)", mp->name, pp->name); g_topology_assert(); gp = NULL; @@ -143,21 +141,19 @@ g_bde_create_geom(struct gctl_req *req, struct g_class *mp, struct g_provider *p g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); - return (error); + gctl_error(req, "could not access consumer"); } - g_topology_unlock(); - g_waitidle(); pass = NULL; key = NULL; do { pass = gctl_get_param(req, "pass", &i); if (pass == NULL || i != SHA512_DIGEST_LENGTH) { - error = gctl_error(req, "No usable key presented"); + gctl_error(req, "No usable key presented"); break; } key = gctl_get_param(req, "key", &i); if (key != NULL && i != 16) { - error = gctl_error(req, "Invalid key presented"); + gctl_error(req, "Invalid key presented"); break; } sectorsize = cp->provider->sectorsize; @@ -194,7 +190,6 @@ g_bde_create_geom(struct gctl_req *req, struct g_class *mp, struct g_provider *p kthread_create(g_bde_worker, gp, &sc->thread, 0, 0, "g_bde %s", gp->name); mtx_unlock(&Giant); - g_topology_lock(); pp = g_new_providerf(gp, gp->name); #if 0 /* @@ -209,28 +204,21 @@ g_bde_create_geom(struct gctl_req *req, struct g_class *mp, struct g_provider *p pp->mediasize = sc->mediasize; pp->sectorsize = sc->sectorsize; g_error_provider(pp, 0); - g_topology_unlock(); break; } while (0); - if (pass != NULL) { + if (pass != NULL) bzero(pass, SHA512_DIGEST_LENGTH); - g_free(pass); - } - if (key != NULL) { + if (key != NULL) bzero(key, 16); - g_free(key); - } - g_topology_lock(); - if (error == 0) { - return (0); - } + if (error == 0) + return; g_access_rel(cp, -1, -1, -1); g_detach(cp); g_destroy_consumer(cp); if (gp->softc != NULL) g_free(gp->softc); g_destroy_geom(gp); - return (error); + return; } @@ -252,7 +240,6 @@ g_bde_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) KASSERT(pp != NULL, ("NULL provider")); if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) return (EBUSY); - g_orphan_provider(pp, ENXIO); sc = gp->softc; cp = LIST_FIRST(&gp->consumer); KASSERT(cp != NULL, ("NULL consumer")); @@ -262,23 +249,38 @@ g_bde_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) KASSERT(error == 0, ("error on close")); g_detach(cp); g_destroy_consumer(cp); - g_topology_unlock(); while (sc->dead != 2 && !LIST_EMPTY(&pp->consumers)) tsleep(sc, PRIBIO, "g_bdedie", hz); - g_waitidle(); - g_topology_lock(); - g_destroy_provider(pp); mtx_destroy(&sc->worklist_mutex); bzero(&sc->key, sizeof sc->key); g_free(sc); - g_destroy_geom(gp); + g_wither_geom(gp, ENXIO); return (0); } +static void +g_bde_ctlreq(struct gctl_req *req, struct g_class *mp, char const *verb) +{ + struct g_geom *gp; + struct g_provider *pp; + + if (!strcmp(verb, "create geom")) { + pp = gctl_get_provider(req, "provider"); + if (pp != NULL) + g_bde_create_geom(req, mp, pp); + } else if (!strcmp(verb, "destroy geom")) { + gp = gctl_get_geom(req, mp, "geom"); + if (gp != NULL) + g_bde_destroy_geom(req, mp, gp); + } else { + gctl_error(req, "unknown verb"); + } +} + static struct g_class g_bde_class = { .name = BDE_CLASS_NAME, - .create_geom = g_bde_create_geom, .destroy_geom = g_bde_destroy_geom, + .ctlreq = g_bde_ctlreq, }; DECLARE_GEOM_CLASS(g_bde_class, g_bde); diff --git a/sys/geom/geom.h b/sys/geom/geom.h index 7bccecc..5dc6925 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -58,6 +58,7 @@ struct gctl_req; struct g_configargs; typedef int g_config_t (struct g_configargs *ca); +typedef void g_ctl_req_t (struct gctl_req *, struct g_class *cp, char const *verb); 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 int g_ctl_config_geom_t (struct gctl_req *, struct g_geom *gp, const char *verb); @@ -88,11 +89,10 @@ struct g_class { const char *name; g_taste_t *taste; g_config_t *config; + g_ctl_req_t *ctlreq; g_init_t *init; g_fini_t *fini; - g_ctl_create_geom_t *create_geom; g_ctl_destroy_geom_t *destroy_geom; - g_ctl_config_geom_t *config_geom; /* * The remaining elements are private */ @@ -304,9 +304,13 @@ extern struct sx topology_lock; #endif /* _KERNEL */ /* geom_ctl.c */ -int gctl_set_param(struct gctl_req *req, const char *param, void *ptr, int len); +void gctl_set_param(struct gctl_req *req, const char *param, void const *ptr, int len); void *gctl_get_param(struct gctl_req *req, const char *param, int *len); +char const *gctl_get_asciiparam(struct gctl_req *req, const char *param); void *gctl_get_paraml(struct gctl_req *req, const char *param, int len); int gctl_error(struct gctl_req *req, const char *fmt, ...); +struct g_class *gctl_get_class(struct gctl_req *req, char const *arg); +struct g_geom *gctl_get_geom(struct gctl_req *req, struct g_class *mpr, char const *arg); +struct g_provider *gctl_get_provider(struct gctl_req *req, char const *arg); #endif /* _GEOM_GEOM_H_ */ diff --git a/sys/geom/geom_bsd.c b/sys/geom/geom_bsd.c index 41a141c..464bfc1 100644 --- a/sys/geom/geom_bsd.c +++ b/sys/geom/geom_bsd.c @@ -670,28 +670,32 @@ g_bsd_callconfig(void *arg, int flag) /* * NB! curthread is user process which GCTL'ed. */ -static int -g_bsd_config(struct gctl_req *req, struct g_geom *gp, const char *verb) +static void +g_bsd_config(struct gctl_req *req, struct g_class *mp, char const *verb) { u_char *label; int error; struct h0h0 h0h0; + struct g_geom *gp; struct g_slicer *gsp; struct g_consumer *cp; struct g_bsd_softc *ms; g_topology_assert(); + gp = gctl_get_geom(req, mp, "geom"); + if (gp == NULL) + return; cp = LIST_FIRST(&gp->consumer); gsp = gp->softc; ms = gsp->softc; if (!strcmp(verb, "read mbroffset")) { - error = gctl_set_param(req, "mbroffset", + gctl_set_param(req, "mbroffset", &ms->mbroffset, sizeof(ms->mbroffset)); - return (error); + return; } else if (!strcmp(verb, "write label")) { label = gctl_get_paraml(req, "label", LABELSIZE); if (label == NULL) - return (EINVAL); + return; h0h0.gp = gp; h0h0.ms = gsp->softc; h0h0.label = label; @@ -699,40 +703,36 @@ g_bsd_config(struct gctl_req *req, struct g_geom *gp, const char *verb) /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access_rel(cp, 1, 1, 1); if (error) { - g_free(label); - return (error); + gctl_error(req, "could not access consumer"); + return; } - g_topology_unlock(); - g_waitfor_event(g_bsd_callconfig, &h0h0, M_WAITOK, gp, NULL); - g_topology_lock(); + g_bsd_callconfig(&h0h0, 0); error = h0h0.error; g_access_rel(cp, -1, -1, -1); - g_free(label); } else if (!strcmp(verb, "write bootcode")) { label = gctl_get_paraml(req, "bootcode", BBSIZE); if (label == NULL) - return (EINVAL); + return; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access_rel(cp, 1, 1, 1); if (error) { - g_free(label); - return (error); + gctl_error(req, "could not access consumer"); + return; } error = g_bsd_writelabel(gp, label); g_access_rel(cp, -1, -1, -1); - g_free(label); } else { - return (gctl_error(req, "Unknown verb parameter")); + gctl_error(req, "Unknown verb parameter"); } - return (error); + return; } /* Finally, register with GEOM infrastructure. */ static struct g_class g_bsd_class = { .name = BSD_CLASS_NAME, .taste = g_bsd_taste, - .config_geom = g_bsd_config, + .ctlreq = g_bsd_config, }; DECLARE_GEOM_CLASS(g_bsd_class, g_bsd); diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c index 053f0ee..bb92d41 100644 --- a/sys/geom/geom_ctl.c +++ b/sys/geom/geom_ctl.c @@ -58,7 +58,6 @@ #include <geom/geom_int.h> #define GCTL_TABLE 1 #include <geom/geom_ctl.h> -#include <geom/geom_ext.h> #include <machine/stdarg.h> @@ -92,27 +91,25 @@ g_ctl_init(void) int gctl_error(struct gctl_req *req, const char *fmt, ...) { - int error; va_list ap; - struct sbuf *sb; - - sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); - if (sb == NULL) { - error = copyout(fmt, req->error, - imin(req->lerror, strlen(fmt) + 1)); - } else { - va_start(ap, fmt); - sbuf_vprintf(sb, fmt, ap); - sbuf_finish(sb); - if (g_debugflags & G_F_CTLDUMP) - printf("gctl %p error \"%s\"\n", req, sbuf_data(sb)); - error = copyout(sbuf_data(sb), req->error, - imin(req->lerror, sbuf_len(sb) + 1)); - } - if (!error) - error = EINVAL; - sbuf_delete(sb); - return (error); + + if (req == NULL) + return (EINVAL); + + /* We only record the first error */ + if (req->nerror) + return (req->nerror); + + va_start(ap, fmt); + sbuf_vprintf(req->serror, fmt, ap); + sbuf_finish(req->serror); + if (g_debugflags & G_F_CTLDUMP) + printf("gctl %p error \"%s\"\n", req, sbuf_data(req->serror)); + req->nerror = copyout(sbuf_data(req->serror), req->error, + imin(req->lerror, sbuf_len(req->serror) + 1)); + if (!req->nerror) + req->nerror = EINVAL; + return (req->nerror); } /* @@ -120,60 +117,51 @@ gctl_error(struct gctl_req *req, const char *fmt, ...) * XXX: this should really be a standard function in the kernel. */ static void * -geom_alloc_copyin(struct gctl_req *req, void *uaddr, size_t len, int *errp) +geom_alloc_copyin(struct gctl_req *req, void *uaddr, size_t len) { - int error; void *ptr; ptr = g_malloc(len, M_WAITOK); if (ptr == NULL) - error = ENOMEM; + req->nerror = ENOMEM; else - error = copyin(uaddr, ptr, len); - if (!error) + req->nerror = copyin(uaddr, ptr, len); + if (!req->nerror) return (ptr); - gctl_error(req, "no access to argument"); - *errp = error; if (ptr != NULL) g_free(ptr); return (NULL); } - -/* - * XXX: This function is a nightmare. It walks through the request and - * XXX: makes sure that the various bits and pieces are there and copies - * XXX: some of them into kernel memory to make things easier. - * XXX: I really wish we had a standard marshalling layer somewhere. - */ - -static int +static void gctl_copyin(struct gctl_req *req) { - int error, i, j; + int error, i; struct gctl_req_arg *ap; char *p; - error = 0; - ap = geom_alloc_copyin(req, req->arg, req->narg * sizeof(*ap), &error); + ap = geom_alloc_copyin(req, req->arg, req->narg * sizeof(*ap)); if (ap == NULL) { - gctl_error(req, "copyin() of arguments failed"); - return (error); + req->nerror = ENOMEM; + req->arg = NULL; + return; } - for (i = 0; !error && i < req->narg; i++) { - 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 (error) - break; - p = NULL; + /* Nothing have been copyin()'ed yet */ + for (i = 0; i < req->narg; i++) { + ap[i].flag &= ~(GCTL_PARAM_NAMEKERNEL|GCTL_PARAM_VALUEKERNEL); + ap[i].flag &= ~GCTL_PARAM_CHANGED; + ap[i].kvalue = NULL; + } + + error = 0; + for (i = 0; i < req->narg; i++) { if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) { - error = gctl_error(req, "wrong param name length"); + error = gctl_error(req, + "wrong param name length %d: %d", i, ap[i].nlen); break; } - p = geom_alloc_copyin(req, ap[i].name, ap[i].nlen, &error); + p = geom_alloc_copyin(req, ap[i].name, ap[i].nlen); if (p == NULL) break; if (p[ap[i].nlen - 1] != '\0') { @@ -182,17 +170,52 @@ gctl_copyin(struct gctl_req *req) break; } ap[i].name = p; - ap[i].nlen = 0; + ap[i].flag |= GCTL_PARAM_NAMEKERNEL; + if (ap[i].len < 0) { + error = gctl_error(req, "negative param length"); + break; + } + if (ap[i].len == 0) { + ap[i].kvalue = ap[i].value; + ap[i].flag |= GCTL_PARAM_VALUEKERNEL; + continue; + } + p = geom_alloc_copyin(req, ap[i].value, ap[i].len); + if (p == NULL) + break; + if ((ap[i].flag & GCTL_PARAM_ASCII) && + p[ap[i].len - 1] != '\0') { + error = gctl_error(req, "unterminated param value"); + g_free(p); + break; + } + ap[i].kvalue = p; + ap[i].flag |= GCTL_PARAM_VALUEKERNEL; } - if (!error) { - req->arg = ap; - return (0); + req->arg = ap; + return; +} + +static void +gctl_copyout(struct gctl_req *req) +{ + int error, i; + struct gctl_req_arg *ap; + + if (req->nerror) + return; + error = 0; + ap = req->arg; + for (i = 0; i < req->narg; i++, ap++) { + if (!(ap->flag & GCTL_PARAM_CHANGED)) + continue; + error = copyout(ap->kvalue, ap->value, ap->len); + if (!error) + continue; + req->nerror = error; + return; } - for (j = 0; j < i; j++) - if (ap[j].nlen == 0 && ap[j].name != NULL) - g_free(ap[j].name); - g_free(ap); - return (error); + return; } static void @@ -200,61 +223,60 @@ gctl_free(struct gctl_req *req) { int i; + if (req->arg == NULL) + return; for (i = 0; i < req->narg; i++) { - if (req->arg[i].nlen == 0 && req->arg[i].name != NULL) + if (req->arg[i].flag & GCTL_PARAM_NAMEKERNEL) g_free(req->arg[i].name); + if ((req->arg[i].flag & GCTL_PARAM_VALUEKERNEL) && + req->arg[i].len > 0) + g_free(req->arg[i].kvalue); } g_free(req->arg); + sbuf_delete(req->serror); } static void gctl_dump(struct gctl_req *req) { u_int i; - int j, error; + int j; struct gctl_req_arg *ap; - void *p; - - printf("Dump of gctl %s request at %p:\n", req->reqt->name, req); - if (req->lerror > 0) { - 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); - g_free(p); - } + printf("Dump of gctl request at %p:\n", req); + if (req->nerror > 0) { + printf(" nerror:\t%d\n", req->nerror); + if (sbuf_len(req->serror) > 0) + printf(" error:\t\"%s\"\n", sbuf_data(req->serror)); } for (i = 0; i < req->narg; i++) { ap = &req->arg[i]; - printf(" param:\t\"%s\"", ap->name); + if (!(ap->flag & GCTL_PARAM_NAMEKERNEL)) + printf(" param:\t%d@%p", ap->nlen, ap->name); + else + printf(" param:\t\"%s\"", ap->name); 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); + if (!(ap->flag & GCTL_PARAM_VALUEKERNEL)) { + printf(" =@ %p", ap->value); + } else if (ap->flag & GCTL_PARAM_ASCII) { + printf("\"%s\"", (char *)ap->kvalue); } else if (ap->len > 0) { - 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); + printf(" %02x", ((u_char *)ap->kvalue)[j]); } else { - printf(" = %p", ap->value); + printf(" = %p", ap->kvalue); } printf("\n"); } } -int -gctl_set_param(struct gctl_req *req, const char *param, void *ptr, int len) +void +gctl_set_param(struct gctl_req *req, const char *param, void const *ptr, int len) { - int i, error; + int i; struct gctl_req_arg *ap; for (i = 0; i < req->narg; i++) { @@ -263,23 +285,24 @@ gctl_set_param(struct gctl_req *req, const char *param, void *ptr, int len) continue; if (!(ap->flag & GCTL_PARAM_WR)) { gctl_error(req, "No write access %s argument", param); - return (EINVAL); + return; } - if (ap->len != len) { + if (ap->len < len) { gctl_error(req, "Wrong length %s argument", param); - return (EINVAL); + return; } - error = copyout(ptr, ap->value, len); - return (error); + bcopy(ptr, ap->kvalue, len); + ap->flag |= GCTL_PARAM_CHANGED; + return; } gctl_error(req, "Missing %s argument", param); - return (EINVAL); + return; } void * gctl_get_param(struct gctl_req *req, const char *param, int *len) { - int i, error, j; + int i; void *p; struct gctl_req_arg *ap; @@ -289,17 +312,36 @@ gctl_get_param(struct gctl_req *req, const char *param, int *len) 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; + p = ap->kvalue; if (len != NULL) - *len = j; + *len = ap->len; + return (p); + } + return (NULL); +} + +char const * +gctl_get_asciiparam(struct gctl_req *req, const char *param) +{ + int i; + char const *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; + p = ap->kvalue; + if (ap->len < 1) { + gctl_error(req, "No length argument (%s)", param); + return (NULL); + } + if (p[ap->len - 1] != '\0') { + gctl_error(req, "Unterminated argument (%s)", param); + return (NULL); + } return (p); } return (NULL); @@ -315,193 +357,105 @@ gctl_get_paraml(struct gctl_req *req, const char *param, int len) if (p == NULL) gctl_error(req, "Missing %s argument", param); else if (i != len) { - g_free(p); p = NULL; gctl_error(req, "Wrong length %s argument", param); } return (p); } -static struct g_class* -gctl_get_class(struct gctl_req *req) +struct g_class * +gctl_get_class(struct gctl_req *req, char const *arg) { - char *p; - int len; + char const *p; struct g_class *cp; - p = gctl_get_param(req, "class", &len); + p = gctl_get_asciiparam(req, arg); 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); + if (!strcmp(p, cp->name)) return (cp); - } } - g_free(p); gctl_error(req, "Class not found"); return (NULL); } -static struct g_geom* -gctl_get_geom(struct gctl_req *req, struct g_class *mpr) +struct g_geom * +gctl_get_geom(struct gctl_req *req, struct g_class *mpr, char const *arg) { - char *p; - int len; + char const *p; struct g_class *mp; struct g_geom *gp; - p = gctl_get_param(req, "geom", &len); + p = gctl_get_asciiparam(req, arg); 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); + if (!strcmp(p, gp->name)) return (gp); - } } } gctl_error(req, "Geom not found"); - g_free(p); return (NULL); } -static struct g_provider* -gctl_get_provider(struct gctl_req *req) +struct g_provider * +gctl_get_provider(struct gctl_req *req, char const *arg) { - char *p; - int len; + char const *p; struct g_class *cp; struct g_geom *gp; struct g_provider *pp; - p = gctl_get_param(req, "provider", &len); + p = gctl_get_asciiparam(req, arg); 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); + if (!strcmp(p, pp->name)) return (pp); - } } } } gctl_error(req, "Provider not found"); - g_free(p); return (NULL); } -static int -gctl_create_geom(struct gctl_req *req) -{ - struct g_class *mp; - struct g_provider *pp; - int error; - - g_topology_assert(); - mp = gctl_get_class(req); - if (mp == NULL) - return (gctl_error(req, "Class not found")); - if (mp->create_geom == NULL) - return (gctl_error(req, "Class has no create_geom method")); - pp = gctl_get_provider(req); - error = mp->create_geom(req, mp, pp); - g_topology_assert(); - return (error); -} - -static int -gctl_destroy_geom(struct gctl_req *req) +static void +g_ctl_req(void *arg, int flag __unused) { struct g_class *mp; - struct g_geom *gp; - int error; + struct gctl_req *req; + char const *verb; g_topology_assert(); - mp = gctl_get_class(req); + req = arg; + mp = gctl_get_class(req, "class"); if (mp == NULL) - return (gctl_error(req, "Class not found")); - if (mp->destroy_geom == NULL) - return (gctl_error(req, "Class has no destroy_geom method")); - gp = gctl_get_geom(req, mp); - if (gp == NULL) - return (gctl_error(req, "Geom not specified")); - if (gp->class != mp) - return (gctl_error(req, "Geom not of specificed class")); - error = mp->destroy_geom(req, mp, gp); + return; + verb = gctl_get_param(req, "verb", NULL); + if (mp->ctlreq == NULL) + gctl_error(req, "Class takes no requests"); + else + mp->ctlreq(req, mp, verb); g_topology_assert(); - return (error); } -static int -gctl_config_geom(struct gctl_req *req) -{ - struct g_class *mp; - struct g_geom *gp; - char *verb; - int error, vlen; - - g_topology_assert(); - mp = gctl_get_class(req); - if (mp == NULL) - return (gctl_error(req, "Class not found")); - if (mp->config_geom == NULL) - return (gctl_error(req, "Class has no config_geom method")); - gp = gctl_get_geom(req, mp); - if (gp == NULL) - return (gctl_error(req, "Geom not specified")); - if (gp->class != mp) - return (gctl_error(req, "Geom not of specificed class")); - verb = gctl_get_param(req, "verb", &vlen); - if (verb == NULL) - return (gctl_error(req, "Missing verb parameter")); - if (vlen < 2) { - g_free(verb); - return (gctl_error(req, "Too short verb parameter")); - } - if (verb[vlen - 1] != '\0') { - g_free(verb); - return (gctl_error(req, "Unterminated verb parameter")); - } - error = mp->config_geom(req, gp, verb); - g_free(verb); - g_topology_assert(); - return (error); -} -/* - * Handle ioctl from libgeom::geom_ctl.c - */ static int g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { - int error; - int i; struct gctl_req *req; req = (void *)data; + req->nerror = 0; + req->serror = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); /* It is an error if we cannot return an error text */ - if (req->lerror < 1) + if (req->lerror < 2) return (EINVAL); if (!useracc(req->error, req->lerror, VM_PROT_WRITE)) return (EINVAL); @@ -511,39 +465,19 @@ g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *t 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 == 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); + gctl_copyin(req); if (g_debugflags & G_F_CTLDUMP) gctl_dump(req); - g_topology_lock(); - switch (req->request) { - case GCTL_CREATE_GEOM: - error = gctl_create_geom(req); - break; - case GCTL_DESTROY_GEOM: - error = gctl_destroy_geom(req); - break; - case GCTL_CONFIG_GEOM: - error = gctl_config_geom(req); - break; - default: - error = gctl_error(req, "XXX: TBD"); - break; + + if (!req->nerror) { + g_waitfor_event(g_ctl_req, req, M_WAITOK, NULL); + gctl_copyout(req); } + gctl_free(req); - g_topology_unlock(); - return (error); + return (req->nerror); } static int @@ -553,12 +487,10 @@ g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) switch(cmd) { case GEOM_CTL: - DROP_GIANT(); error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td); - PICKUP_GIANT(); break; default: - error = ENOTTY; + error = ENOIOCTL; break; } return (error); diff --git a/sys/geom/geom_ctl.h b/sys/geom/geom_ctl.h index 3f7b3d5..fd68bda 100644 --- a/sys/geom/geom_ctl.h +++ b/sys/geom/geom_ctl.h @@ -32,57 +32,51 @@ #ifndef _GEOM_GEOM_CTL_H_ #define _GEOM_GEOM_CTL_H_ -/* - * Version number. Used to check consistency between kernel and libgeom. - */ -#define GCTL_VERSION 1 +#include <sys/ioccom.h> /* - * Primitives. + * Version number. Used to check consistency between kernel and libgeom. */ -enum gctl_request { - GCTL_INVALID_REQUEST = 0, +#define GCTL_VERSION 2 - GCTL_CREATE_GEOM, - GCTL_DESTROY_GEOM, +struct gctl_req_arg { + u_int nlen; + char *name; + off_t offset; + int flag; + int len; + void *value; + /* kernel only fields */ + void *kvalue; +}; - GCTL_ATTACH, - GCTL_DETACH, +#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 - GCTL_CREATE_PROVIDER, - GCTL_DESTROY_PROVIDER, +/* These are used in the kernel only */ +#define GCTL_PARAM_NAMEKERNEL 8 +#define GCTL_PARAM_VALUEKERNEL 16 +#define GCTL_PARAM_CHANGED 32 - GCTL_INSERT_GEOM, - GCTL_ELIMINATE_GEOM, +struct gctl_req { + u_int version; + u_int serial; + u_int narg; + struct gctl_req_arg *arg; + u_int lerror; + char *error; + struct gctl_req_table *reqt; - GCTL_CONFIG_GEOM, + /* kernel only fields */ + int nerror; + struct sbuf *serror; }; -#ifdef GCTL_TABLE -struct gctl_req_table { - int class; - int geom; - int provider; - int consumer; - int params; - char *name; - enum gctl_request request; -} gcrt[] = { -/* Cl Ge Pr Co Pa Name Request */ - { 1, 0, 1, 0, 1, "create geom", GCTL_CREATE_GEOM }, - { 0, 1, 0, 0, 1, "destroy geom", GCTL_DESTROY_GEOM }, - { 0, 1, 1, 0, 1, "attach", GCTL_ATTACH }, - { 0, 1, 1, 0, 1, "detach", GCTL_DETACH }, - { 0, 1, 0, 0, 1, "create provider", GCTL_CREATE_PROVIDER }, - { 0, 1, 1, 0, 1, "destroy provider", GCTL_DESTROY_PROVIDER }, - { 1, 1, 1, 0, 1, "insert geom", GCTL_INSERT_GEOM }, - { 0, 1, 0, 0, 1, "eliminate geom", GCTL_ELIMINATE_GEOM }, - { 0, 1, 0, 0, 1, "config geom", GCTL_CONFIG_GEOM }, +#define GEOM_CTL _IOW('G', GCTL_VERSION, struct gctl_req) - /* Terminator entry */ - { 1, 1, 1, 1, 1, "*INVALID*", GCTL_INVALID_REQUEST } -}; +#define PATH_GEOM_CTL "geom.ctl" -#endif /* GCTL_TABLE */ #endif /* _GEOM_GEOM_CTL_H_ */ diff --git a/sys/geom/geom_ext.h b/sys/geom/geom_ext.h deleted file mode 100644 index a48fc0b..0000000 --- a/sys/geom/geom_ext.h +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * Copyright (c) 2003 Poul-Henning Kamp - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the authors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file defines the interface between libgeom and the geom control device - * in the kernel, the interfaces defined herein are to be considered private - * and may only be used by libgeom. Applications wishing to interact with - * the geom subsystem must use libgeoms published APIs. - * - * $FreeBSD$ - */ - -#ifndef _GEOM_GEOM_EXT_H_ -#define _GEOM_GEOM_EXT_H_ - -#include <sys/ioccom.h> -#include <geom/geom_ctl.h> - -struct gctl_req_arg { - u_int nlen; - char *name; - off_t offset; - int flag; - int len; - void *value; -}; - -#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 gctl_request request; - u_int narg; - struct gctl_req_arg *arg; - u_int lerror; - char *error; - struct gctl_req_table *reqt; -}; - -#define GEOM_CTL _IOW('G', GCTL_VERSION, struct gctl_req) - -#define PATH_GEOM_CTL "geom.ctl" - -#endif /* _GEOM_GEOM_EXT_H_ */ diff --git a/sys/geom/geom_sunlabel.c b/sys/geom/geom_sunlabel.c index f37c0dc..cfade35 100644 --- a/sys/geom/geom_sunlabel.c +++ b/sys/geom/geom_sunlabel.c @@ -169,22 +169,26 @@ g_sunlabel_callconfig(void *arg, int flag) /* * NB! curthread is user process which GCTL'ed. */ -static int -g_sunlabel_config(struct gctl_req *req, struct g_geom *gp, const char *verb) +static void +g_sunlabel_config(struct gctl_req *req, struct g_class *mp, const char *verb) { u_char *label; int error, i; struct g_hh01 h0h0; struct g_slicer *gsp; + struct g_geom *gp; struct g_consumer *cp; g_topology_assert(); + gp = gctl_get_geom(req, mp, "geom"); + if (gp == NULL) + return; cp = LIST_FIRST(&gp->consumer); gsp = gp->softc; if (!strcmp(verb, "write label")) { label = gctl_get_paraml(req, "label", SUN_SIZE); if (label == NULL) - return (EINVAL); + return; h0h0.gp = gp; h0h0.ms = gsp->softc; h0h0.label = label; @@ -192,24 +196,20 @@ g_sunlabel_config(struct gctl_req *req, struct g_geom *gp, const char *verb) /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access_rel(cp, 1, 1, 1); if (error) { - g_free(label); - return (error); + gctl_error(req, "could not access consumer"); + return; } - g_topology_unlock(); - g_waitfor_event(g_sunlabel_callconfig, &h0h0, M_WAITOK, gp, NULL); - g_topology_lock(); - error = h0h0.error; + g_sunlabel_callconfig(&h0h0, 0); g_access_rel(cp, -1, -1, -1); - g_free(label); } else if (!strcmp(verb, "write bootcode")) { label = gctl_get_paraml(req, "bootcode", SUN_BOOTSIZE); if (label == NULL) - return (EINVAL); + return; /* XXX: Does this reference register with our selfdestruct code ? */ error = g_access_rel(cp, 1, 1, 1); if (error) { - g_free(label); - return (error); + gctl_error(req, "could not access consumer"); + return; } for (i = 0; i < SUN_NPART; i++) { if (gsp->slices[i].length <= SUN_BOOTSIZE) @@ -219,12 +219,9 @@ g_sunlabel_config(struct gctl_req *req, struct g_geom *gp, const char *verb) SUN_BOOTSIZE - SUN_SIZE); } g_access_rel(cp, -1, -1, -1); - g_free(label); } else { - return (gctl_error(req, "Unknown verb parameter")); + gctl_error(req, "Unknown verb parameter"); } - - return (error); } static struct g_geom * @@ -278,7 +275,7 @@ g_sunlabel_taste(struct g_class *mp, struct g_provider *pp, int flags) static struct g_class g_sunlabel_class = { .name = SUNLABEL_CLASS_NAME, .taste = g_sunlabel_taste, - .config_geom = g_sunlabel_config, + .ctlreq = g_sunlabel_config, }; DECLARE_GEOM_CLASS(g_sunlabel_class, g_sunlabel); |