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
This commit is contained in:
Poul-Henning Kamp 2002-10-14 10:05:23 +00:00
parent d0e17c1b91
commit 6b4abfd6eb
3 changed files with 168 additions and 41 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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);
}