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:
Poul-Henning Kamp 2002-10-07 06:25:26 +00:00
parent db8c52408d
commit adfa3213c7
4 changed files with 26 additions and 42 deletions

View File

@ -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 */
#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 {
u_long cmd;
void *data;
int fflag;
struct thread *td;
d_ioctl_t *func;
dev_t dev;
};
#ifdef _KERNEL

View File

@ -231,14 +231,12 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
int i, error;
u_int u;
struct g_ioctl *gio;
#if 0
struct sbuf *usb, *sb;
#endif
gp = dev->si_drv1;
cp = dev->si_drv2;
pp2 = cp->provider;
gp2 = pp2->geom;
gio = NULL;
error = 0;
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)
dev->si_flags |= SI_DUMPDEV;
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:
gio = g_malloc(sizeof *gio, M_WAITOK);
gio = g_malloc(sizeof *gio, M_WAITOK | M_ZERO);
gio->cmd = cmd;
gio->data = data;
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);
else
error = g_io_getattr("GEOM::ioctl", cp, &i, gio);
g_free(gio);
break;
}
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();
if (error == ENOIOCTL) {
if (g_debugflags & G_T_TOPOLOGY) {

View File

@ -131,26 +131,6 @@ g_disk_done(struct bio *bp)
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
g_disk_start(struct bio *bp)
{
@ -191,16 +171,20 @@ g_disk_start(struct bio *bp)
g_disk_kerneldump(bp, dp);
else if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
bp->bio_length == sizeof *gio) {
g_call_me(g_disk_ioctl, bp);
return;
gio = (struct g_ioctl *)bp->bio_data;
gio->func = devsw(dp->d_dev)->d_ioctl;
gio->dev = dp->d_dev;
error = EDIRIOCTL;
} else
error = ENOIOCTL;
break;
case BIO_SETATTR:
if (!strcmp(bp->bio_attribute, "GEOM::ioctl") &&
bp->bio_length == sizeof *gio) {
g_call_me(g_disk_ioctl, bp);
return;
gio = (struct g_ioctl *)bp->bio_data;
gio->func = devsw(dp->d_dev)->d_ioctl;
gio->dev = dp->d_dev;
error = EDIRIOCTL;
} else
error = ENOIOCTL;
break;

View File

@ -180,6 +180,7 @@ __END_DECLS
#define ERESTART (-1) /* restart syscall */
#define EJUSTRETURN (-2) /* don't modify regs, just return */
#define ENOIOCTL (-3) /* ioctl not handled by this layer */
#define EDIRIOCTL (-4) /* do direct ioctl in GEOM */
#endif
#endif