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:
parent
d0e17c1b91
commit
6b4abfd6eb
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user