diff --git a/sys/geom/geom.h b/sys/geom/geom.h index c687e0e2d93d..c053fcb6cd83 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -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 diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c index c926e18df088..1b30703691aa 100644 --- a/sys/geom/geom_dev.c +++ b/sys/geom/geom_dev.c @@ -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) { diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index 1f1d362f51e4..be9008ca53d4 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -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; diff --git a/sys/sys/errno.h b/sys/sys/errno.h index 70ad24a6c0e9..2e93afd94816 100644 --- a/sys/sys/errno.h +++ b/sys/sys/errno.h @@ -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