Copyin and copyout are only possible from a process-native thread,
and therefore we need a way for ioctl handlers to run in that thread in GEOM. Rather than invent a complicated registration system to recognize which ioctl handler to use for a given ioctl, we still schedule all ioctls down the tree as bio transactions but add a special return code that means "call me directly" and have the geom_dev layer do that. Use this for all ioctls that make it as far as a diskdriver to avoid any backwards compatibility problems. Requested by: scottl Sponsored by: DARPA & NAI Labs
This commit is contained in:
parent
db8c52408d
commit
adfa3213c7
|
@ -225,11 +225,18 @@ int g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length);
|
||||||
|
|
||||||
/* geom_kern.c / geom_kernsim.c */
|
/* geom_kern.c / geom_kernsim.c */
|
||||||
|
|
||||||
|
#ifndef _SYS_CONF_H_
|
||||||
|
typedef int d_ioctl_t(dev_t dev, u_long cmd, caddr_t data,
|
||||||
|
int fflag, struct thread *td);
|
||||||
|
#endif
|
||||||
|
|
||||||
struct g_ioctl {
|
struct g_ioctl {
|
||||||
u_long cmd;
|
u_long cmd;
|
||||||
void *data;
|
void *data;
|
||||||
int fflag;
|
int fflag;
|
||||||
struct thread *td;
|
struct thread *td;
|
||||||
|
d_ioctl_t *func;
|
||||||
|
dev_t dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
|
|
@ -231,14 +231,12 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
|
||||||
int i, error;
|
int i, error;
|
||||||
u_int u;
|
u_int u;
|
||||||
struct g_ioctl *gio;
|
struct g_ioctl *gio;
|
||||||
#if 0
|
|
||||||
struct sbuf *usb, *sb;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gp = dev->si_drv1;
|
gp = dev->si_drv1;
|
||||||
cp = dev->si_drv2;
|
cp = dev->si_drv2;
|
||||||
pp2 = cp->provider;
|
pp2 = cp->provider;
|
||||||
gp2 = pp2->geom;
|
gp2 = pp2->geom;
|
||||||
|
gio = NULL;
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
DROP_GIANT();
|
DROP_GIANT();
|
||||||
|
@ -274,21 +272,9 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
|
||||||
if (!error)
|
if (!error)
|
||||||
dev->si_flags |= SI_DUMPDEV;
|
dev->si_flags |= SI_DUMPDEV;
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
case GEOMGETCONF:
|
|
||||||
/* we bogusly pass cp to avoid getting any consumers listed */
|
|
||||||
sb = g_conf_specific(gp2->class, gp2, pp2, cp);
|
|
||||||
usb = (struct sbuf *)data;
|
|
||||||
if (usb->s_size - 1 < sbuf_len(sb))
|
|
||||||
error = ENOMEM;
|
|
||||||
else
|
|
||||||
error = copyout(sbuf_data(sb), usb->s_buf, sbuf_len(sb) + 1);
|
|
||||||
if (!error)
|
|
||||||
usb->s_len = sbuf_len(sb);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
gio = g_malloc(sizeof *gio, M_WAITOK);
|
gio = g_malloc(sizeof *gio, M_WAITOK | M_ZERO);
|
||||||
gio->cmd = cmd;
|
gio->cmd = cmd;
|
||||||
gio->data = data;
|
gio->data = data;
|
||||||
gio->fflag = fflag;
|
gio->fflag = fflag;
|
||||||
|
@ -298,11 +284,17 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
|
||||||
error = g_io_setattr("GEOM::ioctl", cp, i, gio);
|
error = g_io_setattr("GEOM::ioctl", cp, i, gio);
|
||||||
else
|
else
|
||||||
error = g_io_getattr("GEOM::ioctl", cp, &i, gio);
|
error = g_io_getattr("GEOM::ioctl", cp, &i, gio);
|
||||||
g_free(gio);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PICKUP_GIANT();
|
PICKUP_GIANT();
|
||||||
|
if (error == EDIRIOCTL) {
|
||||||
|
KASSERT(gio != NULL, ("NULL gio but EDIRIOCTL"));
|
||||||
|
KASSERT(gio->func != NULL, ("NULL function but EDIRIOCTL"));
|
||||||
|
error = (gio->func)(gio->dev, cmd, data, fflag, td);
|
||||||
|
}
|
||||||
|
if (gio != NULL)
|
||||||
|
g_free(gio);
|
||||||
g_waitidle();
|
g_waitidle();
|
||||||
if (error == ENOIOCTL) {
|
if (error == ENOIOCTL) {
|
||||||
if (g_debugflags & G_T_TOPOLOGY) {
|
if (g_debugflags & G_T_TOPOLOGY) {
|
||||||
|
|
|
@ -131,26 +131,6 @@ g_disk_done(struct bio *bp)
|
||||||
mtx_lock(&Giant);
|
mtx_lock(&Giant);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
g_disk_ioctl(void *arg)
|
|
||||||
{
|
|
||||||
struct bio *bp;
|
|
||||||
dev_t dev;
|
|
||||||
struct disk *dp;
|
|
||||||
struct g_ioctl *gio;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
bp = arg;
|
|
||||||
dp = bp->bio_to->geom->softc;
|
|
||||||
dev = dp->d_dev;
|
|
||||||
gio = (struct g_ioctl *)bp->bio_data;
|
|
||||||
mtx_lock(&Giant);
|
|
||||||
error = devsw(dev)->d_ioctl(dev, gio->cmd,
|
|
||||||
gio->data, gio->fflag, gio->td);
|
|
||||||
mtx_unlock(&Giant);
|
|
||||||
g_io_deliver(bp, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_disk_start(struct bio *bp)
|
g_disk_start(struct bio *bp)
|
||||||
{
|
{
|
||||||
|
@ -191,16 +171,20 @@ g_disk_start(struct bio *bp)
|
||||||
g_disk_kerneldump(bp, dp);
|
g_disk_kerneldump(bp, dp);
|
||||||
else if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
|
else if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
|
||||||
bp->bio_length == sizeof *gio) {
|
bp->bio_length == sizeof *gio) {
|
||||||
g_call_me(g_disk_ioctl, bp);
|
gio = (struct g_ioctl *)bp->bio_data;
|
||||||
return;
|
gio->func = devsw(dp->d_dev)->d_ioctl;
|
||||||
|
gio->dev = dp->d_dev;
|
||||||
|
error = EDIRIOCTL;
|
||||||
} else
|
} else
|
||||||
error = ENOIOCTL;
|
error = ENOIOCTL;
|
||||||
break;
|
break;
|
||||||
case BIO_SETATTR:
|
case BIO_SETATTR:
|
||||||
if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
|
if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
|
||||||
bp->bio_length == sizeof *gio) {
|
bp->bio_length == sizeof *gio) {
|
||||||
g_call_me(g_disk_ioctl, bp);
|
gio = (struct g_ioctl *)bp->bio_data;
|
||||||
return;
|
gio->func = devsw(dp->d_dev)->d_ioctl;
|
||||||
|
gio->dev = dp->d_dev;
|
||||||
|
error = EDIRIOCTL;
|
||||||
} else
|
} else
|
||||||
error = ENOIOCTL;
|
error = ENOIOCTL;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -180,6 +180,7 @@ __END_DECLS
|
||||||
#define ERESTART (-1) /* restart syscall */
|
#define ERESTART (-1) /* restart syscall */
|
||||||
#define EJUSTRETURN (-2) /* don't modify regs, just return */
|
#define EJUSTRETURN (-2) /* don't modify regs, just return */
|
||||||
#define ENOIOCTL (-3) /* ioctl not handled by this layer */
|
#define ENOIOCTL (-3) /* ioctl not handled by this layer */
|
||||||
|
#define EDIRIOCTL (-4) /* do direct ioctl in GEOM */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue