summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/geom/geom.h54
-rw-r--r--sys/geom/geom_ctl.c36
-rw-r--r--sys/geom/geom_subr.c119
3 files changed, 168 insertions, 41 deletions
diff --git a/sys/geom/geom.h b/sys/geom/geom.h
index fa34bda..289c9e1 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 b6e18c7..8e1ce84 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
@@ -172,6 +172,37 @@ g_ctl_ioctl_getconf(dev_t dev, u_long cmd, caddr_t data, int fflag, struct threa
}
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)
{
int error;
@@ -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 45130c6..5fc726d 100644
--- a/sys/geom/geom_subr.c
+++ b/sys/geom/geom_subr.c
@@ -572,43 +572,6 @@ g_class_by_name(char *name)
}
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)
{
struct g_class *mp;
@@ -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);
+}
OpenPOWER on IntegriCloud