From ddbf51af0cc86b76184f366c365200ac587887b1 Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Fri, 17 Jan 2003 14:53:53 +0000 Subject: [PATCH] Find places to store the previously implicityly passed unit number in the three configuration ioctls which need a unit number. Add a "ccd.ctl" device for config operations. Implement ioctls on ccd.ctl which rely on the explicityly passed unit numbers. Update ccdconfig to use the new ccd.ctl interface. Add code to the kernel to detect old ccdconfig binaries, and whine about it. Add code to ccdconfig to detect old kernels, and whine about it. These two compatibility measures will be retained only for a limited period since they are in the way of GEOM'ification of ccd. --- sbin/ccdconfig/ccdconfig.c | 36 +++++------ sbin/ccdconfig/pathnames.h | 3 + sys/dev/ccd/ccd.c | 129 +++++++++++++++++++++++++++++++++++-- sys/geom/geom_ccd.c | 129 +++++++++++++++++++++++++++++++++++-- 4 files changed, 265 insertions(+), 32 deletions(-) diff --git a/sbin/ccdconfig/ccdconfig.c b/sbin/ccdconfig/ccdconfig.c index 290839951606..c1c7ad5308da 100644 --- a/sbin/ccdconfig/ccdconfig.c +++ b/sbin/ccdconfig/ccdconfig.c @@ -182,6 +182,7 @@ do_single(int argc, char **argv, int action) i = 1; continue; } + ccio.ccio_size = ccd; if (do_io(ccd, CCDIOCCLR, &ccio)) i = 1; else @@ -251,6 +252,7 @@ do_single(int argc, char **argv, int action) ccio.ccio_ndisks = i; ccio.ccio_ileave = ileave; ccio.ccio_flags = flags; + ccio.ccio_size = ccd; if (do_io(ccd, CCDIOCSET, &ccio)) { free(disks); @@ -379,11 +381,19 @@ do_io(int unit, u_long cmd, struct ccd_ioctl *cciop) char *cp; char *path; - asprintf(&path, "%sccd%dc", _PATH_DEV, unit); + asprintf(&path, "%s%s", _PATH_DEV, _PATH_CCDCTL); if ((fd = open(path, O_RDWR, 0640)) < 0) { - warn("open: %s", path); - return (1); + asprintf(&path, "%sccd%dc", _PATH_DEV, unit); + if ((fd = open(path, O_RDWR, 0640)) < 0) { + warn("open: %s", path); + return (1); + } + fprintf(stderr, + "***WARNING***: Kernel older than ccdconfig(8), please upgrade it.\n"); + fprintf(stderr, + "***WARNING***: Continuing in 30 seconds\n"); + sleep(30); } if (ioctl(fd, cmd, cciop) < 0) { @@ -510,19 +520,9 @@ print_ccd_info(struct ccd_s *cs) warnx("can't read component info: invalid ccd name: %s", cp); return; } - cpps.size = 0; - if (do_io(ccd, CCDCPPINFO, (struct ccd_ioctl *) &cpps)) { - printf("\n"); - warnx("can't read component info"); - return; - } + cpps.size = 1024; cpps.buffer = alloca(cpps.size); - if (cpps.buffer == NULL) { - printf("\n"); - warn("ccd%d: can't allocate memory for component info", - cs->sc_unit); - return; - } + memcpy(cpps.buffer, &ccd, sizeof ccd); if (do_io(ccd, CCDCPPINFO, (struct ccd_ioctl *) &cpps)) { printf("\n"); warnx("can't read component info"); @@ -530,11 +530,11 @@ print_ccd_info(struct ccd_s *cs) } /* Display component info. */ - for (cp = cpps.buffer; cp - cpps.buffer < cpps.size; cp += strlen(cp) + 1) { + for (cp = cpps.buffer; *cp && cp - cpps.buffer < cpps.size; cp += strlen(cp) + 1) { printf((cp + strlen(cp) + 1) < (cpps.buffer + cpps.size) ? - "%s " : "%s\n", cp); - fflush(stdout); + "%s " : "%s", cp); } + printf("\n"); return; } diff --git a/sbin/ccdconfig/pathnames.h b/sbin/ccdconfig/pathnames.h index f8da9e08e7c9..538cfeda096d 100644 --- a/sbin/ccdconfig/pathnames.h +++ b/sbin/ccdconfig/pathnames.h @@ -30,6 +30,9 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD$ */ #define _PATH_CCDCONF "/etc/ccd.conf" +#define _PATH_CCDCTL "ccd.ctl" diff --git a/sys/dev/ccd/ccd.c b/sys/dev/ccd/ccd.c index 7b2ea9ad555c..c012cebbd104 100644 --- a/sys/dev/ccd/ccd.c +++ b/sys/dev/ccd/ccd.c @@ -124,8 +124,13 @@ static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, ""); #endif -#define ccdunit(x) dkunit(x) -#define ccdpart(x) dkpart(x) +static u_int +ccdunit(dev_t dev) +{ + return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f)); +} + +#define ccdpart(x) (minor(x) & 7) /* This is how mirroring works (only writes are special): @@ -161,10 +166,15 @@ struct ccdbuf { #define IS_ALLOCATED(unit) (ccdfind(unit) != NULL) #define IS_INITED(cs) (((cs)->sc_flags & CCDF_INITED) != 0) + +static dev_t ccdctldev; + + static d_open_t ccdopen; static d_close_t ccdclose; static d_strategy_t ccdstrategy; static d_ioctl_t ccdioctl; +static d_ioctl_t ccdioctltoo; static d_psize_t ccdsize; #define NCCDFREEHIWAT 16 @@ -354,6 +364,9 @@ static void ccdattach() { + ccdctldev = make_dev(&ccd_cdevsw, 0xffff00ff, + UID_ROOT, GID_OPERATOR, 0640, "ccd.ctl"); + ccdctldev->si_drv1 = ccdctldev; EVENTHANDLER_REGISTER(dev_clone, ccd_clone, 0, 1000); } @@ -517,7 +530,7 @@ ccdinit(struct ccd_s *cs, char **cpaths, struct thread *td) * * Lost space must be taken into account when calculating the * overall size. Half the space is lost when CCDF_MIRROR is - * specified. One disk is lost when CCDF_PARITY is specified. + * specified. */ if (cs->sc_flags & CCDF_UNIFORM) { for (ci = cs->sc_cinfo; @@ -617,7 +630,7 @@ ccdinterleave(struct ccd_s *cs, int unit) * Trivial case: no interleave (actually interleave of disk size). * Each table entry represents a single component in its entirety. * - * An interleave of 0 may not be used with a mirror or parity setup. + * An interleave of 0 may not be used with a mirror setup. */ if (cs->sc_ileave == 0) { bn = 0; @@ -718,6 +731,8 @@ ccdopen(dev_t dev, int flags, int fmt, struct thread *td) struct disklabel *lp; int error = 0, part, pmask; + if (dev->si_drv1 == dev) + return (0); #ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdopen(%p, %x)\n", dev, flags); @@ -762,6 +777,8 @@ ccdclose(dev_t dev, int flags, int fmt, struct thread *td) struct ccd_s *cs; int error = 0, part; + if (dev->si_drv1 == dev) + return (0); #ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdclose(%p, %x)\n", dev, flags); @@ -795,6 +812,10 @@ ccdstrategy(struct bio *bp) int wlabel; struct disklabel *lp; + if (bp->bio_dev->si_drv1 == bp->bio_dev) { + biofinish(bp, NULL, ENXIO); + return; + } #ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdstrategy(%p): unit %d\n", bp, unit); @@ -1243,7 +1264,96 @@ ccdiodone(struct bio *ibp) static int ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) { - int unit = ccdunit(dev); + struct ccd_ioctl *ccio; + u_int unit; + dev_t dev2; + int error; + + if (dev->si_drv1 != dev) { + switch (cmd) { + case CCDIOCSET: + case CCDIOCCLR: + case CCDCONFINFO: + case CCDCPPINFO: + printf("*** WARNING: upgrade your ccdconfig(8) binary\n"); + printf("*** WARNING: continuing in 30 seconds\n"); + tsleep(dev, PRIBIO, "ccdbug", hz * 30); + break; + } + return ccdioctltoo(dev, cmd, data, flag, td); + } + switch (cmd) { + case CCDIOCSET: + case CCDIOCCLR: + ccio = (struct ccd_ioctl *)data; + unit = ccio->ccio_size; + dev2 = makedev(CDEV_MAJOR, unit * 8 + 2); + if (!(dev2->si_flags & SI_NAMED)) { + dev2 = make_dev(&ccd_cdevsw, unit * 8 + 2, + UID_ROOT, GID_OPERATOR, 0640, "ccd%dc", unit); + ccdnew(unit); + } + return (ccdioctltoo(dev2, cmd, data, flag, td)); + case CCDCONFINFO: + { + int ninit = 0; + struct ccdconf *conf = (struct ccdconf *)data; + struct ccd_s *tmpcs; + struct ccd_s *ubuf = conf->buffer; + + /* XXX: LOCK(unique unit numbers) */ + LIST_FOREACH(tmpcs, &ccd_softc_list, list) + if (IS_INITED(tmpcs)) + ninit++; + + if (conf->size == 0) { + conf->size = sizeof(struct ccd_s) * ninit; + return (0); + } else if ((conf->size / sizeof(struct ccd_s) != ninit) || + (conf->size % sizeof(struct ccd_s) != 0)) { + /* XXX: UNLOCK(unique unit numbers) */ + return (EINVAL); + } + + ubuf += ninit; + LIST_FOREACH(tmpcs, &ccd_softc_list, list) { + if (!IS_INITED(tmpcs)) + continue; + error = copyout(tmpcs, --ubuf, + sizeof(struct ccd_s)); + if (error != 0) + /* XXX: UNLOCK(unique unit numbers) */ + return (error); + } + /* XXX: UNLOCK(unique unit numbers) */ + return (0); + } + + case CCDCPPINFO: + { + struct ccdcpps *cpps = (struct ccdcpps *)data; + char *ubuf = cpps->buffer; + + + error = copyin(ubuf, &unit, sizeof (unit)); + if (error) + return (error); + + if (!IS_ALLOCATED(unit)) + return (ENXIO); + dev2 = makedev(CDEV_MAJOR, unit * 8 + 2); + return (ccdioctltoo(dev2, cmd, data, flag, td)); + } + + default: + return (ENXIO); + } +} + +static int +ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) +{ + int unit; int i, j, lookedup = 0, error = 0; int part, pmask, s; struct ccd_s *cs; @@ -1251,6 +1361,7 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) char **cpp; struct vnode **vpp; + unit = ccdunit(dev); if (!IS_ALLOCATED(unit)) return (ENXIO); cs = ccdfind(unit); @@ -1469,8 +1580,8 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) if (cpps->size == 0) { cpps->size = len; break; - } else if (cpps->size != len) { - return (EINVAL); + } else if (cpps->size < len) { + return (ENOMEM); } for (i = 0; i < cs->sc_nccdisks; ++i) { @@ -1481,6 +1592,7 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) return (error); ubuf += len; } + return(copyout("", ubuf, 1)); } break; @@ -1545,6 +1657,9 @@ ccdsize(dev_t dev) struct ccd_s *cs; int part, size; + if (dev->si_drv1 == dev) + return (-1); + if (ccdopen(dev, 0, S_IFCHR, curthread)) return (-1); diff --git a/sys/geom/geom_ccd.c b/sys/geom/geom_ccd.c index 7b2ea9ad555c..c012cebbd104 100644 --- a/sys/geom/geom_ccd.c +++ b/sys/geom/geom_ccd.c @@ -124,8 +124,13 @@ static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, ""); #endif -#define ccdunit(x) dkunit(x) -#define ccdpart(x) dkpart(x) +static u_int +ccdunit(dev_t dev) +{ + return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f)); +} + +#define ccdpart(x) (minor(x) & 7) /* This is how mirroring works (only writes are special): @@ -161,10 +166,15 @@ struct ccdbuf { #define IS_ALLOCATED(unit) (ccdfind(unit) != NULL) #define IS_INITED(cs) (((cs)->sc_flags & CCDF_INITED) != 0) + +static dev_t ccdctldev; + + static d_open_t ccdopen; static d_close_t ccdclose; static d_strategy_t ccdstrategy; static d_ioctl_t ccdioctl; +static d_ioctl_t ccdioctltoo; static d_psize_t ccdsize; #define NCCDFREEHIWAT 16 @@ -354,6 +364,9 @@ static void ccdattach() { + ccdctldev = make_dev(&ccd_cdevsw, 0xffff00ff, + UID_ROOT, GID_OPERATOR, 0640, "ccd.ctl"); + ccdctldev->si_drv1 = ccdctldev; EVENTHANDLER_REGISTER(dev_clone, ccd_clone, 0, 1000); } @@ -517,7 +530,7 @@ ccdinit(struct ccd_s *cs, char **cpaths, struct thread *td) * * Lost space must be taken into account when calculating the * overall size. Half the space is lost when CCDF_MIRROR is - * specified. One disk is lost when CCDF_PARITY is specified. + * specified. */ if (cs->sc_flags & CCDF_UNIFORM) { for (ci = cs->sc_cinfo; @@ -617,7 +630,7 @@ ccdinterleave(struct ccd_s *cs, int unit) * Trivial case: no interleave (actually interleave of disk size). * Each table entry represents a single component in its entirety. * - * An interleave of 0 may not be used with a mirror or parity setup. + * An interleave of 0 may not be used with a mirror setup. */ if (cs->sc_ileave == 0) { bn = 0; @@ -718,6 +731,8 @@ ccdopen(dev_t dev, int flags, int fmt, struct thread *td) struct disklabel *lp; int error = 0, part, pmask; + if (dev->si_drv1 == dev) + return (0); #ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdopen(%p, %x)\n", dev, flags); @@ -762,6 +777,8 @@ ccdclose(dev_t dev, int flags, int fmt, struct thread *td) struct ccd_s *cs; int error = 0, part; + if (dev->si_drv1 == dev) + return (0); #ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdclose(%p, %x)\n", dev, flags); @@ -795,6 +812,10 @@ ccdstrategy(struct bio *bp) int wlabel; struct disklabel *lp; + if (bp->bio_dev->si_drv1 == bp->bio_dev) { + biofinish(bp, NULL, ENXIO); + return; + } #ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdstrategy(%p): unit %d\n", bp, unit); @@ -1243,7 +1264,96 @@ ccdiodone(struct bio *ibp) static int ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) { - int unit = ccdunit(dev); + struct ccd_ioctl *ccio; + u_int unit; + dev_t dev2; + int error; + + if (dev->si_drv1 != dev) { + switch (cmd) { + case CCDIOCSET: + case CCDIOCCLR: + case CCDCONFINFO: + case CCDCPPINFO: + printf("*** WARNING: upgrade your ccdconfig(8) binary\n"); + printf("*** WARNING: continuing in 30 seconds\n"); + tsleep(dev, PRIBIO, "ccdbug", hz * 30); + break; + } + return ccdioctltoo(dev, cmd, data, flag, td); + } + switch (cmd) { + case CCDIOCSET: + case CCDIOCCLR: + ccio = (struct ccd_ioctl *)data; + unit = ccio->ccio_size; + dev2 = makedev(CDEV_MAJOR, unit * 8 + 2); + if (!(dev2->si_flags & SI_NAMED)) { + dev2 = make_dev(&ccd_cdevsw, unit * 8 + 2, + UID_ROOT, GID_OPERATOR, 0640, "ccd%dc", unit); + ccdnew(unit); + } + return (ccdioctltoo(dev2, cmd, data, flag, td)); + case CCDCONFINFO: + { + int ninit = 0; + struct ccdconf *conf = (struct ccdconf *)data; + struct ccd_s *tmpcs; + struct ccd_s *ubuf = conf->buffer; + + /* XXX: LOCK(unique unit numbers) */ + LIST_FOREACH(tmpcs, &ccd_softc_list, list) + if (IS_INITED(tmpcs)) + ninit++; + + if (conf->size == 0) { + conf->size = sizeof(struct ccd_s) * ninit; + return (0); + } else if ((conf->size / sizeof(struct ccd_s) != ninit) || + (conf->size % sizeof(struct ccd_s) != 0)) { + /* XXX: UNLOCK(unique unit numbers) */ + return (EINVAL); + } + + ubuf += ninit; + LIST_FOREACH(tmpcs, &ccd_softc_list, list) { + if (!IS_INITED(tmpcs)) + continue; + error = copyout(tmpcs, --ubuf, + sizeof(struct ccd_s)); + if (error != 0) + /* XXX: UNLOCK(unique unit numbers) */ + return (error); + } + /* XXX: UNLOCK(unique unit numbers) */ + return (0); + } + + case CCDCPPINFO: + { + struct ccdcpps *cpps = (struct ccdcpps *)data; + char *ubuf = cpps->buffer; + + + error = copyin(ubuf, &unit, sizeof (unit)); + if (error) + return (error); + + if (!IS_ALLOCATED(unit)) + return (ENXIO); + dev2 = makedev(CDEV_MAJOR, unit * 8 + 2); + return (ccdioctltoo(dev2, cmd, data, flag, td)); + } + + default: + return (ENXIO); + } +} + +static int +ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) +{ + int unit; int i, j, lookedup = 0, error = 0; int part, pmask, s; struct ccd_s *cs; @@ -1251,6 +1361,7 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) char **cpp; struct vnode **vpp; + unit = ccdunit(dev); if (!IS_ALLOCATED(unit)) return (ENXIO); cs = ccdfind(unit); @@ -1469,8 +1580,8 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) if (cpps->size == 0) { cpps->size = len; break; - } else if (cpps->size != len) { - return (EINVAL); + } else if (cpps->size < len) { + return (ENOMEM); } for (i = 0; i < cs->sc_nccdisks; ++i) { @@ -1481,6 +1592,7 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) return (error); ubuf += len; } + return(copyout("", ubuf, 1)); } break; @@ -1545,6 +1657,9 @@ ccdsize(dev_t dev) struct ccd_s *cs; int part, size; + if (dev->si_drv1 == dev) + return (-1); + if (ccdopen(dev, 0, S_IFCHR, curthread)) return (-1);