From 497c33476706e093b6cf0d881d4301e5466d0d43 Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Mon, 1 Sep 2003 20:45:32 +0000 Subject: [PATCH] Simplify the ioctl handling in GEOM. This replaces the current ioctl processing with a direct call path from geom_dev() where the ioctl arrives (from SPECFS) to any directly connected GEOM class. The inverse of the above is no longer supported. This is the situation were you have one or more intervening GEOM classes, for instance a BSDlabel on top of a MBR or PC98. If you want to issue MBR or PC98 specific ioctls, you will need to issue them on a MBR or PC98 providers. This paves the way for inviting CD's, FD's and other special cases inside GEOM. --- sys/geom/geom.h | 19 +--- sys/geom/geom_bsd.c | 215 +++++++++++++++---------------------------- sys/geom/geom_dev.c | 45 +-------- sys/geom/geom_disk.c | 30 ++++-- sys/geom/geom_mbr.c | 74 +++++---------- sys/geom/geom_pc98.c | 72 +++++---------- 6 files changed, 146 insertions(+), 309 deletions(-) diff --git a/sys/geom/geom.h b/sys/geom/geom.h index cdb5de22e42d..40ba390beb74 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -64,8 +64,8 @@ typedef int g_ctl_destroy_geom_t (struct gctl_req *, struct g_class *cp, struct typedef int g_ctl_config_geom_t (struct gctl_req *, struct g_geom *gp, const char *verb); typedef void g_init_t (struct g_class *mp); typedef void g_fini_t (struct g_class *mp); -typedef struct g_geom * g_taste_t (struct g_class *, struct g_provider *, - int flags); +typedef struct g_geom * g_taste_t (struct g_class *, struct g_provider *, int flags); +typedef int g_ioctl_t(struct g_provider *pp, u_long cmd, void *data, struct thread *td); #define G_TF_NORMAL 0 #define G_TF_INSIST 1 #define G_TF_TRANSPARENT 2 @@ -116,6 +116,7 @@ struct g_geom { g_dumpconf_t *dumpconf; g_access_t *access; g_orphan_t *orphan; + g_ioctl_t *ioctl; void *softc; unsigned flags; #define G_GEOM_WITHER 1 @@ -231,20 +232,6 @@ 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; - void *dev; -}; - #ifdef _KERNEL struct g_kerneldump { diff --git a/sys/geom/geom_bsd.c b/sys/geom/geom_bsd.c index 4f4d5659339c..1a309eb8c228 100644 --- a/sys/geom/geom_bsd.c +++ b/sys/geom/geom_bsd.c @@ -267,98 +267,6 @@ g_bsd_writelabel(struct g_geom *gp, u_char *bootcode) return(error); } - -/* - * Implement certain ioctls to modify disklabels with. This function - * is called by the event handler thread with topology locked as result - * of the g_post_event() in g_bsd_start(). It is not necessary to keep - * topology locked all the time but make sure to return with topology - * locked as well. - */ - -static void -g_bsd_ioctl(void *arg, int flag) -{ - struct bio *bp; - struct g_geom *gp; - struct g_ioctl *gio; - u_char *label; - int error; - - g_topology_assert(); - bp = arg; - if (flag == EV_CANCEL) { - g_io_deliver(bp, ENXIO); - return; - } - - gp = bp->bio_to->geom; - gio = (struct g_ioctl *)bp->bio_data; - - label = g_malloc(LABELSIZE, M_WAITOK); - - /* The disklabel to set is the ioctl argument. */ - bsd_disklabel_le_enc(label, gio->data); - - /* Validate and modify our slice instance to match. */ - error = g_bsd_modify(gp, label); /* Picks up topology lock on success. */ - g_free(label); - if (error || gio->cmd == DIOCSDINFO) { - g_io_deliver(bp, error); - return; - } - - KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl")); - g_io_deliver(bp, g_bsd_writelabel(gp, NULL)); -} - -/* - * Rewrite the bootblock, which is BBSIZE bytes from the start of the disk. - * We punch down the disklabel where we expect it to be before writing. - */ -static int -g_bsd_diocbsdbb(dev_t dev, u_long cmd __unused, caddr_t data, int fflag __unused, struct thread *td __unused) -{ - struct g_geom *gp; - struct g_slicer *gsp; - struct g_bsd_softc *ms; - struct g_consumer *cp; - u_char *buf; - void *p; - int error, i; - uint64_t sum; - - /* Get hold of the interesting bits from the bio. */ - gp = (void *)dev; - gsp = gp->softc; - ms = gsp->softc; - - /* The disklabel to set is the ioctl argument. */ - buf = g_malloc(BBSIZE, M_WAITOK); - p = *(void **)data; - error = copyin(p, buf, BBSIZE); - if (!error) { - DROP_GIANT(); - g_topology_lock(); - /* Validate and modify our slice instance to match. */ - error = g_bsd_modify(gp, buf + ms->labeloffset); - if (!error) { - cp = LIST_FIRST(&gp->consumer); - if (ms->labeloffset == ALPHA_LABEL_OFFSET) { - sum = 0; - for (i = 0; i < 63; i++) - sum += le64dec(buf + i * 8); - le64enc(buf + 504, sum); - } - error = g_write_data(cp, 0, buf, BBSIZE); - } - g_topology_unlock(); - PICKUP_GIANT(); - } - g_free(buf); - return (error); -} - /* * If the user tries to overwrite our disklabel through an open partition * or via a magicwrite config call, we end up here and try to prevent @@ -406,6 +314,79 @@ g_bsd_hotwrite(void *arg, int flag) * * Don't grab the topology lock. * * Don't call biowait, g_getattr(), g_setattr() or g_read_data() */ +static int +g_bsd_ioctl(struct g_provider *pp, u_long cmd, void * data, struct thread *td) +{ + struct g_geom *gp; + struct g_bsd_softc *ms; + struct g_slicer *gsp; + u_char *label; + int error; + + gp = pp->geom; + gsp = gp->softc; + ms = gsp->softc; + + switch(cmd) { + case DIOCGDINFO: + /* Return a copy of the disklabel to userland. */ + bsd_disklabel_le_dec(ms->label, data, MAXPARTITIONS); + return(0); + case DIOCBSDBB: { + struct g_consumer *cp; + u_char *buf; + void *p; + int error, i; + uint64_t sum; + + /* The disklabel to set is the ioctl argument. */ + buf = g_malloc(BBSIZE, M_WAITOK); + p = *(void **)data; + error = copyin(p, buf, BBSIZE); + if (!error) { + /* XXX: Rude, but supposedly safe */ + DROP_GIANT(); + g_topology_lock(); + /* Validate and modify our slice instance to match. */ + error = g_bsd_modify(gp, buf + ms->labeloffset); + if (!error) { + cp = LIST_FIRST(&gp->consumer); + if (ms->labeloffset == ALPHA_LABEL_OFFSET) { + sum = 0; + for (i = 0; i < 63; i++) + sum += le64dec(buf + i * 8); + le64enc(buf + 504, sum); + } + error = g_write_data(cp, 0, buf, BBSIZE); + } + g_topology_unlock(); + PICKUP_GIANT(); + } + g_free(buf); + return (error); + } + case DIOCSDINFO: + case DIOCWDINFO: { + label = g_malloc(LABELSIZE, M_WAITOK); + + /* The disklabel to set is the ioctl argument. */ + bsd_disklabel_le_enc(label, data); + + DROP_GIANT(); + g_topology_lock(); + /* Validate and modify our slice instance to match. */ + error = g_bsd_modify(gp, label); + if (error == 0 && cmd == DIOCWDINFO) + error = g_bsd_writelabel(gp, NULL); + g_topology_unlock(); + PICKUP_GIANT(); + g_free(label); + return(error); + } + default: + return (ENOIOCTL); + } +} static int g_bsd_start(struct bio *bp) @@ -413,61 +394,16 @@ g_bsd_start(struct bio *bp) struct g_geom *gp; struct g_bsd_softc *ms; struct g_slicer *gsp; - struct g_ioctl *gio; - int error; gp = bp->bio_to->geom; gsp = gp->softc; ms = gsp->softc; - switch(bp->bio_cmd) { - case BIO_GETATTR: + if (bp->bio_cmd == BIO_GETATTR) { if (g_handleattr(bp, "BSD::labelsum", ms->labelsum, sizeof(ms->labelsum))) return (1); - break; - default: - KASSERT(0 == 1, ("Unknown bio_cmd in g_bsd_start (%d)", - bp->bio_cmd)); - } - - /* We only handle ioctl(2) requests of the right format. */ - if (strcmp(bp->bio_attribute, "GEOM::ioctl")) - return (0); - else if (bp->bio_length != sizeof(*gio)) - return (0); - - /* Get hold of the ioctl parameters. */ - gio = (struct g_ioctl *)bp->bio_data; - - switch (gio->cmd) { - case DIOCGDINFO: - /* Return a copy of the disklabel to userland. */ - bsd_disklabel_le_dec(ms->label, gio->data, MAXPARTITIONS); - g_io_deliver(bp, 0); - return (1); - case DIOCBSDBB: - gio->func = g_bsd_diocbsdbb; - gio->dev = (void *)gp; - g_io_deliver(bp, EDIRIOCTL); - return (1); - case DIOCSDINFO: - case DIOCWDINFO: - /* - * These we cannot do without the topology lock and some - * some I/O requests. Ask the event-handler to schedule - * us in a less restricted environment. - */ - error = g_post_event(g_bsd_ioctl, bp, M_NOWAIT, gp, NULL); - if (error) - g_io_deliver(bp, error); - /* - * We must return non-zero to indicate that we will deal - * with this bio, even though we have not done so yet. - */ - return (1); - default: - return (0); } + return (0); } /* @@ -559,6 +495,7 @@ g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags) * routine which the "slice" code should call at the right time */ gp->dumpconf = g_bsd_dumpconf; + gp->ioctl = g_bsd_ioctl; /* Get the geom_slicer softc from the geom. */ gsp = gp->softc; diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c index 470ac8d894a0..8da252f67b1b 100644 --- a/sys/geom/geom_dev.c +++ b/sys/geom/geom_dev.c @@ -279,17 +279,14 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) struct g_kerneldump kd; int i, error; u_int u; - struct g_ioctl *gio; gp = dev->si_drv1; cp = dev->si_drv2; - gio = NULL; error = 0; KASSERT(cp->acr || cp->acw, ("Consumer with zero access count in g_dev_ioctl")); - gio = NULL; i = IOCPARM_LEN(cmd); switch (cmd) { case DIOCGSECTORSIZE: @@ -331,46 +328,14 @@ g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) break; default: - gio = g_malloc(sizeof *gio, M_WAITOK | M_ZERO); - gio->cmd = cmd; - gio->data = data; - gio->fflag = fflag; - gio->td = td; - i = sizeof *gio; - /* - * We always issue ioctls as getattr since the direction of data - * movement in ioctl is no indication of the ioctl being a "set" - * or "get" type ioctl or if such simplistic terms even apply - */ - error = g_io_getattr("GEOM::ioctl", cp, &i, gio); - break; + if (cp->provider->geom->ioctl != NULL) { + error = cp->provider->geom->ioctl(cp->provider, cmd, data, td); + if (error != ENOIOCTL) + return (error); + } } - 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); - } g_waitidle(); - if (gio != NULL && (error == EOPNOTSUPP || error == ENOIOCTL)) { - if (g_debugflags & G_T_TOPOLOGY) { - i = IOCGROUP(cmd); - printf("IOCTL(0x%lx) \"%s\"", cmd, gp->name); - if (i > ' ' && i <= '~') - printf(" '%c'", (int)IOCGROUP(cmd)); - else - printf(" 0x%lx", IOCGROUP(cmd)); - printf("/%ld ", cmd & 0xff); - if (cmd & IOC_IN) - printf("I"); - if (cmd & IOC_OUT) - printf("O"); - printf("(%ld) = ENOIOCTL\n", IOCPARM_LEN(cmd)); - } - error = ENOTTY; - } - if (gio != NULL) - g_free(gio); return (error); } diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index 43c861412cb3..5746415e24b8 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -194,12 +194,29 @@ g_disk_done(struct bio *bp) mtx_unlock(&g_disk_done_mtx); } +static int +g_disk_ioctl(struct g_provider *pp, u_long cmd, void * data, struct thread *td) +{ + struct g_geom *gp; + struct disk *dp; + int error; + + gp = pp->geom; + dp = gp->softc; + + if (dp->d_ioctl == NULL) + return (ENOIOCTL); + g_disk_lock_giant(dp); + error = dp->d_ioctl(dp, cmd, data, 0, td); + g_disk_unlock_giant(dp); + return(error); +} + static void g_disk_start(struct bio *bp) { struct bio *bp2, *bp3; struct disk *dp; - struct g_ioctl *gio; int error; off_t off; @@ -264,15 +281,7 @@ g_disk_start(struct bio *bp) break; else if (!strcmp(bp->bio_attribute, "GEOM::kerneldump")) g_disk_kerneldump(bp, dp); - else if ((g_debugflags & G_F_DISKIOCTL) && - (dp->d_ioctl != NULL) && - !strcmp(bp->bio_attribute, "GEOM::ioctl") && - bp->bio_length == sizeof *gio) { - gio = (struct g_ioctl *)bp->bio_data; - gio->dev = dp; - gio->func = (d_ioctl_t *)(dp->d_ioctl); - error = EDIRIOCTL; - } else + else error = ENOIOCTL; break; default: @@ -317,6 +326,7 @@ g_disk_create(void *arg, int flag) gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit); gp->start = g_disk_start; gp->access = g_disk_access; + gp->ioctl = g_disk_ioctl; gp->softc = dp; gp->dumpconf = g_disk_dumpconf; pp = g_new_providerf(gp, "%s", gp->name); diff --git a/sys/geom/geom_mbr.c b/sys/geom/geom_mbr.c index 7d5994ad9007..877f090c4f78 100644 --- a/sys/geom/geom_mbr.c +++ b/sys/geom/geom_mbr.c @@ -152,42 +152,36 @@ g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, u_char *sec0) return (0); } -static void -g_mbr_ioctl(void *arg, int flag) +static int +g_mbr_ioctl(struct g_provider *pp, u_long cmd, void *data, struct thread *td) { - struct bio *bp; struct g_geom *gp; - struct g_slicer *gsp; struct g_mbr_softc *ms; - struct g_ioctl *gio; + struct g_slicer *gsp; struct g_consumer *cp; - u_char *sec0; int error; - bp = arg; - if (flag == EV_CANCEL) { - g_io_deliver(bp, ENXIO); - return; - } - gp = bp->bio_to->geom; + gp = pp->geom; gsp = gp->softc; ms = gsp->softc; - gio = (struct g_ioctl *)bp->bio_data; - /* The disklabel to set is the ioctl argument. */ - sec0 = gio->data; - - error = g_mbr_modify(gp, ms, sec0); - if (error) { - g_io_deliver(bp, error); - return; + switch(cmd) { + case DIOCSMBR: { + DROP_GIANT(); + g_topology_lock(); + /* Validate and modify our slicer instance to match. */ + error = g_mbr_modify(gp, ms, data); + cp = LIST_FIRST(&gp->consumer); + error = g_write_data(cp, 0, data, 512); + g_topology_unlock(); + PICKUP_GIANT(); + return(error); + } + default: + return (ENOIOCTL); } - cp = LIST_FIRST(&gp->consumer); - error = g_write_data(cp, 0, sec0, 512); - g_io_deliver(bp, error); } - static int g_mbr_start(struct bio *bp) { @@ -195,8 +189,7 @@ g_mbr_start(struct bio *bp) struct g_geom *gp; struct g_mbr_softc *mp; struct g_slicer *gsp; - struct g_ioctl *gio; - int idx, error; + int idx; pp = bp->bio_to; idx = pp->index; @@ -211,33 +204,7 @@ g_mbr_start(struct bio *bp) return (1); } - /* We only handle ioctl(2) requests of the right format. */ - if (strcmp(bp->bio_attribute, "GEOM::ioctl")) - return (0); - else if (bp->bio_length != sizeof(*gio)) - return (0); - - /* Get hold of the ioctl parameters. */ - gio = (struct g_ioctl *)bp->bio_data; - - switch (gio->cmd) { - case DIOCSMBR: - /* - * These we cannot do without the topology lock and some - * some I/O requests. Ask the event-handler to schedule - * us in a less restricted environment. - */ - error = g_post_event(g_mbr_ioctl, bp, M_NOWAIT, gp, NULL); - if (error) - g_io_deliver(bp, error); - /* - * We must return non-zero to indicate that we will deal - * with this bio, even though we have not done so yet. - */ - return (1); - default: - return (0); - } + return (0); } static void @@ -275,6 +242,7 @@ g_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist) return (NULL); g_topology_unlock(); gp->dumpconf = g_mbr_dumpconf; + gp->ioctl = g_mbr_ioctl; do { if (gp->rank != 2 && insist == 0) break; diff --git a/sys/geom/geom_pc98.c b/sys/geom/geom_pc98.c index b6d2c2113d53..6be3ed9ba32b 100644 --- a/sys/geom/geom_pc98.c +++ b/sys/geom/geom_pc98.c @@ -134,39 +134,34 @@ g_pc98_modify(struct g_geom *gp, struct g_pc98_softc *ms, u_char *sec) return (0); } -static void -g_pc98_ioctl(void *arg, int flag) +static int +g_pc98_ioctl(struct g_provider *pp, u_long cmd, void *data, struct thread *td) { - struct bio *bp; struct g_geom *gp; - struct g_slicer *gsp; struct g_pc98_softc *ms; - struct g_ioctl *gio; + struct g_slicer *gsp; struct g_consumer *cp; - u_char *sec; int error; - bp = arg; - if (flag == EV_CANCEL) { - g_io_deliver(bp, ENXIO); - return; - } - gp = bp->bio_to->geom; + gp = pp->geom; gsp = gp->softc; ms = gsp->softc; - gio = (struct g_ioctl *)bp->bio_data; - /* The disklabel to set is the ioctl argument. */ - sec = gio->data; - - error = g_pc98_modify(gp, ms, sec); - if (error) { - g_io_deliver(bp, error); - return; + switch(cmd) { + case DIOCSPC98: { + DROP_GIANT(); + g_topology_lock(); + /* Validate and modify our slicer instance to match. */ + error = g_pc98_modify(gp, ms, data); + cp = LIST_FIRST(&gp->consumer); + error = g_write_data(cp, 0, data, 8192); + g_topology_unlock(); + PICKUP_GIANT(); + return(error); + } + default: + return (ENOIOCTL); } - cp = LIST_FIRST(&gp->consumer); - error = g_write_data(cp, 0, sec, 8192); - g_io_deliver(bp, error); } static int @@ -176,8 +171,7 @@ g_pc98_start(struct bio *bp) struct g_geom *gp; struct g_pc98_softc *mp; struct g_slicer *gsp; - struct g_ioctl *gio; - int idx, error; + int idx; pp = bp->bio_to; idx = pp->index; @@ -192,32 +186,7 @@ g_pc98_start(struct bio *bp) return (1); } - /* We only handle ioctl(2) requests of the right format. */ - if (strcmp(bp->bio_attribute, "GEOM::ioctl")) - return (0); - else if (bp->bio_length != sizeof(*gio)) - return (0); - /* Get hold of the ioctl parameters. */ - gio = (struct g_ioctl *)bp->bio_data; - - switch (gio->cmd) { - case DIOCSPC98: - /* - * These we cannot do without the topology lock and some - * some I/O requests. Ask the event-handler to schedule - * us in a less restricted environment. - */ - error = g_post_event(g_pc98_ioctl, bp, M_NOWAIT, gp, NULL); - if (error) - g_io_deliver(bp, error); - /* - * We must return non-zero to indicate that we will deal - * with this bio, even though we have not done so yet. - */ - return (1); - default: - return (0); - } + return (0); } static void @@ -270,6 +239,7 @@ g_pc98_taste(struct g_class *mp, struct g_provider *pp, int flags) return (NULL); g_topology_unlock(); gp->dumpconf = g_pc98_dumpconf; + gp->ioctl = g_pc98_ioctl; do { if (gp->rank != 2 && flags == G_TF_NORMAL) break;