From d855c322044dff7473bc10f78b996febcd65bb07 Mon Sep 17 00:00:00 2001 From: phk Date: Mon, 14 Oct 2002 10:05:23 +0000 Subject: [PATCH] Implement the GEOMCONFIGGEOM ioctl which can be used to manually create and configure an instance of a class on a give provider. Sponsored by: DARPA & NAI Labs --- sys/geom/geom.h | 54 ++++++++++++++++++-- sys/geom/geom_ctl.c | 36 ++++++++++++- sys/geom/geom_subr.c | 119 +++++++++++++++++++++++++++++-------------- 3 files changed, 168 insertions(+), 41 deletions(-) diff --git a/sys/geom/geom.h b/sys/geom/geom.h index fa34bdad384..289c9e1d263 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -61,9 +61,9 @@ struct g_event; struct thread; struct bio; struct sbuf; +struct g_createargs; -typedef struct g_geom * g_create_geom_t (struct g_class *mp, - struct g_provider *pp, char *name); +typedef int g_create_geom_t (struct g_createargs *ca); typedef struct g_geom * g_taste_t (struct g_class *, struct g_provider *, int flags); #define G_TF_NORMAL 0 @@ -171,6 +171,26 @@ struct g_provider { off_t mediasize; }; +/* + * This gadget is used by userland to pinpoint a particular instance of + * something in the kernel. The name is unreadable on purpose, people + * should not encounter it directly but use library functions to deal + * with it. + * If len is zero, "id" contains a cast of the kernel pointer where the + * entity is located, (likely derived from the "id=" attribute in the + * XML config) and the g_id*() functions will validate this before allowing + * it to be used. + * If len is non-zero, it is the strlen() of the name which is pointed to + * by "name". + */ +struct geomidorname { + u_int len; + union { + const char *name; + uintptr_t id; + } u; +}; + /* geom_dump.c */ void g_hexdump(void *ptr, int length); void g_trace(int level, char *, ...); @@ -191,7 +211,6 @@ int g_access_abs(struct g_consumer *cp, int read, int write, int exclusive); int g_access_rel(struct g_consumer *cp, int read, int write, int exclusive); void g_add_class(struct g_class *mp); int g_attach(struct g_consumer *cp, struct g_provider *pp); -struct g_geom *g_create_geomf(char *class, struct g_provider *, char *fmt, ...); void g_destroy_consumer(struct g_consumer *cp); void g_destroy_geom(struct g_geom *pp); void g_destroy_provider(struct g_provider *pp); @@ -211,6 +230,10 @@ void g_spoil(struct g_provider *pp, struct g_consumer *cp); int g_std_access(struct g_provider *pp, int dr, int dw, int de); void g_std_done(struct bio *bp); void g_std_spoiled(struct g_consumer *cp); +struct g_class *g_idclass(struct geomidorname *); +struct g_geom *g_idgeom(struct geomidorname *); +struct g_provider *g_idprovider(struct geomidorname *); + /* geom_io.c */ struct bio * g_clone_bio(struct bio *); @@ -305,12 +328,37 @@ extern struct sx topology_lock; /* * IOCTLS for talking to the geom.ctl device. */ + struct geomgetconf { char *ptr; u_int len; }; #define GEOMGETCONF _IOW('G', 0, struct geomgetconf) +struct g_createargs { + /* Valid on call */ + struct g_class *class; + struct g_provider *provider; + u_int flag; + u_int len; + void *ptr; + /* Valid on return */ + struct g_geom *geom; +}; + +struct geomconfiggeom { + /* Valid on call */ + struct geomidorname class; + struct geomidorname provider; + u_int flag; + u_int len; + void *ptr; + /* Valid on return */ + uintptr_t geom; +}; +#define GEOMCONFIGGEOM _IOW('G', 0, struct geomconfiggeom) + + /* geom_enc.c */ uint16_t g_dec_be2(u_char *p); uint32_t g_dec_be4(u_char *p); diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c index b6e18c72cbf..8e1ce84ec09 100644 --- a/sys/geom/geom_ctl.c +++ b/sys/geom/geom_ctl.c @@ -147,7 +147,7 @@ g_ctl_start(struct bio *bp) } /* - * All the stuff above is really just needed to get to this one. + * All the stuff above is really just needed to get to the stuff below */ static int @@ -171,6 +171,37 @@ g_ctl_ioctl_getconf(dev_t dev, u_long cmd, caddr_t data, int fflag, struct threa return(error); } +static int +g_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) +{ + struct geomconfiggeom *gcp; + struct g_createargs ga; + int error; + + error = 0; + gcp = (struct geomconfiggeom *)data; + ga.class = g_idclass(&gcp->class); + if (ga.class == NULL) + return (EINVAL); + if (ga.class->create_geom == NULL) + return (EOPNOTSUPP); + ga.provider = g_idprovider(&gcp->provider); + if (ga.provider == NULL) + return (EINVAL); + ga.len = gcp->len; + if (gcp->len > 64 * 1024) + return (EINVAL); + else if (gcp->len == 0) { + ga.ptr = NULL; + } else { + ga.ptr = g_malloc(gcp->len, M_WAITOK); + copyin(gcp->ptr, ga.ptr, gcp->len); + } + error = ga.class->create_geom(&ga); + gcp->geom = (uintptr_t)ga.geom; + return(error); +} + static int g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { @@ -182,6 +213,9 @@ g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) case GEOMGETCONF: error = g_ctl_ioctl_getconf(dev, cmd, data, fflag, td); break; + case GEOMCONFIGGEOM: + error = g_ctl_ioctl_configgeom(dev, cmd, data, fflag, td); + break; default: error = ENOTTY; break; diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c index 45130c6f8d9..5fc726d006c 100644 --- a/sys/geom/geom_subr.c +++ b/sys/geom/geom_subr.c @@ -571,43 +571,6 @@ g_class_by_name(char *name) return (NULL); } -struct g_geom * -g_create_geomf(char *class, struct g_provider *pp, char *fmt, ...) -{ - va_list ap; - struct sbuf *sb; - char *s; - struct g_class *mp; - struct g_geom *gp; - - g_trace(G_T_TOPOLOGY, "g_create_geom(%s, %p(%s))", class, - pp, pp == NULL ? "" : pp->name); - g_topology_assert(); - gp = NULL; - mp = g_class_by_name(class); - if (mp == NULL) - return (NULL); - if (fmt != NULL) { - va_start(ap, fmt); - mtx_lock(&Giant); - sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); - sbuf_vprintf(sb, fmt, ap); - sbuf_finish(sb); - mtx_unlock(&Giant); - s = sbuf_data(sb); - } else { - s = NULL; - } - if (pp != NULL) - gp = mp->taste(mp, pp, G_TF_INSIST); - if (gp == NULL && mp->create_geom == NULL) - return (NULL); - if (gp == NULL) - gp = mp->create_geom(mp, pp, s); - /* XXX: delete sbuf */ - return (gp); -} - struct g_geom * g_insert_geom(char *class, struct g_consumer *cp) { @@ -699,4 +662,86 @@ g_sanity(void *ptr) } } +struct g_class * +g_idclass(struct geomidorname *p) +{ + struct g_class *mp; + char *n; + + if (p->len == 0) { + LIST_FOREACH(mp, &g_classes, class) + if ((uintptr_t)mp == p->u.id) + return (mp); + return (NULL); + } + n = g_malloc(p->len + 1, M_WAITOK); + if (copyin(p->u.name, n, p->len) == 0) { + n[p->len] = '\0'; + LIST_FOREACH(mp, &g_classes, class) + if (!bcmp(n, mp->name, p->len + 1)) { + g_free(n); + return (mp); + } + } + g_free(n); + return (NULL); +} + +struct g_geom * +g_idgeom(struct geomidorname *p) +{ + struct g_class *mp; + struct g_geom *gp; + char *n; + + if (p->len == 0) { + LIST_FOREACH(mp, &g_classes, class) + LIST_FOREACH(gp, &mp->geom, geom) + if ((uintptr_t)gp == p->u.id) + return (gp); + return (NULL); + } + n = g_malloc(p->len + 1, M_WAITOK); + if (copyin(p->u.name, n, p->len) == 0) { + n[p->len] = '\0'; + LIST_FOREACH(mp, &g_classes, class) + LIST_FOREACH(gp, &mp->geom, geom) + if (!bcmp(n, gp->name, p->len + 1)) { + g_free(n); + return (gp); + } + } + g_free(n); + return (NULL); +} +struct g_provider * +g_idprovider(struct geomidorname *p) +{ + struct g_class *mp; + struct g_geom *gp; + struct g_provider *pp; + char *n; + + if (p->len == 0) { + LIST_FOREACH(mp, &g_classes, class) + LIST_FOREACH(gp, &mp->geom, geom) + LIST_FOREACH(pp, &gp->provider, provider) + if ((uintptr_t)pp == p->u.id) + return (pp); + return (NULL); + } + n = g_malloc(p->len + 1, M_WAITOK); + if (copyin(p->u.name, n, p->len) == 0) { + n[p->len] = '\0'; + LIST_FOREACH(mp, &g_classes, class) + LIST_FOREACH(gp, &mp->geom, geom) + LIST_FOREACH(pp, &gp->provider, provider) + if (!bcmp(n, pp->name, p->len + 1)) { + g_free(n); + return (pp); + } + } + g_free(n); + return (NULL); +} -- 2.45.2