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 */
|
||||
|
||||
#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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user