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);