From df622d54f83b5932893226e7f53ffdd71f147d6e Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Mon, 9 Jun 2003 19:25:07 +0000 Subject: [PATCH] GEOMification of CCD. You need your kernel and ccdconfig(8) to be in sync, particularly if your source tree is on a ccd device. --- UPDATING | 8 + sbin/ccdconfig/ccdconfig.c | 234 ++----- sys/conf/files | 3 +- sys/dev/ccd/ccd.c | 1322 ------------------------------------ sys/sys/ccdvar.h | 120 ---- 5 files changed, 79 insertions(+), 1608 deletions(-) delete mode 100644 sys/dev/ccd/ccd.c delete mode 100644 sys/sys/ccdvar.h diff --git a/UPDATING b/UPDATING index eab88d2ce5a8..339bde9bfb66 100644 --- a/UPDATING +++ b/UPDATING @@ -17,6 +17,14 @@ NOTE TO PEOPLE WHO THINK THAT 5.0-CURRENT IS SLOW: developers choose to disable these features on build machines to maximize performance. +20030509: + CCD has been changed to be a fully GEOMified class. Kernel + and ccdconfig(8) needs to be in sync, this is particularly + important to remember beforehand if your source tree is on + a ccd device. Consider making a copy of the old ccdconfig + into /boot/kernel.good or wherever you keep your backup + kernel. + 20030505: Kerberos 5 (Heimdal) is now built by default. Setting MAKE_KERBEROS5 no longer has any effect. If you do NOT diff --git a/sbin/ccdconfig/ccdconfig.c b/sbin/ccdconfig/ccdconfig.c index 636127ca8b04..6113ae6f605f 100644 --- a/sbin/ccdconfig/ccdconfig.c +++ b/sbin/ccdconfig/ccdconfig.c @@ -1,6 +1,5 @@ -/* $NetBSD: ccdconfig.c,v 1.2.2.1 1995/11/11 02:43:35 thorpej Exp $ */ - /* + * Copyright (c) 2003 Poul-Henning Kamp * Copyright (c) 1995 Jason R. Thorpe. * All rights reserved. * @@ -37,13 +36,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include #include #include #include #include -#include #include #include #include @@ -52,8 +48,8 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#define CCDF_UNIFORM 0x02 /* use LCCD of sizes for uniform interleave */ +#define CCDF_MIRROR 0x04 /* use mirroring */ #include "pathnames.h" @@ -63,10 +59,13 @@ static const char *ccdconf = _PATH_CCDCONF; struct flagval { const char *fv_flag; - int fv_val; + int fv_val; } flagvaltab[] = { { "CCDF_UNIFORM", CCDF_UNIFORM }, + { "uniform", CCDF_UNIFORM }, { "CCDF_MIRROR", CCDF_MIRROR }, + { "mirror", CCDF_MIRROR }, + { "none", 0 }, { NULL, 0 }, }; @@ -76,8 +75,6 @@ struct flagval { #define CCD_UNCONFIGALL 3 /* unconfigure all devices */ #define CCD_DUMP 4 /* dump a ccd's configuration */ -static int checkdev(char *); -static int do_io(int, u_long, struct ccd_ioctl *); static int do_single(int, char **, int); static int do_all(int); static int dump_ccd(int, char **); @@ -134,10 +131,10 @@ main(int argc, char *argv[]) if (options > 1) usage(); - if (modfind("ccd") < 0) { + if (modfind("g_ccd") < 0) { /* Not present in kernel, try loading it */ - if (kldload("ccd") < 0 || modfind("ccd") < 0) - warn("ccd module not available!"); + if (kldload("g_ccd") < 0 || modfind("g_ccd") < 0) + warn("g_ccd module not available!"); } switch (action) { @@ -162,17 +159,18 @@ main(int argc, char *argv[]) static int do_single(int argc, char **argv, int action) { - struct ccd_ioctl ccio; - char *cp, *cp2, **disks; - int ccd, noflags = 0, i, ileave, flags = 0, j; - u_int u; - - bzero(&ccio, sizeof(ccio)); + char *cp, *cp2; + int ccd, noflags = 0, i, ileave, flags = 0; + struct gctl_req *grq; + char const *errstr; + char buf1[BUFSIZ]; + int ex; /* * If unconfiguring, all arguments are treated as ccds. */ if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) { + ex = 0; for (i = 0; argc != 0; ) { cp = *argv++; --argc; if ((ccd = resolve_ccdname(cp)) < 0) { @@ -180,14 +178,24 @@ do_single(int argc, char **argv, int action) i = 1; continue; } - ccio.ccio_size = ccd; - if (do_io(ccd, CCDIOCCLR, &ccio)) - i = 1; - else + grq = gctl_get_handle(); + gctl_ro_param(grq, "verb", -1, "destroy geom"); + gctl_ro_param(grq, "class", -1, "CCD"); + sprintf(buf1, "ccd%d", ccd); + gctl_ro_param(grq, "geom", -1, buf1); + errstr = gctl_issue(grq); + if (errstr == NULL) { if (verbose) printf("%s unconfigured\n", cp); + gctl_free(grq); + continue; + } + warnx( + "%s\nor possibly kernel and ccdconfig out of sync", + errstr); + ex = 1; } - return (i); + return (ex); } /* Make sure there are enough arguments. */ @@ -228,56 +236,36 @@ do_single(int argc, char **argv, int action) return (1); } } - - /* Next is the list of disks to make the ccd from. */ - disks = malloc(argc * sizeof(char *)); - if (disks == NULL) { - warnx("no memory to configure ccd"); - return (1); + grq = gctl_get_handle(); + gctl_ro_param(grq, "verb", -1, "create geom"); + gctl_ro_param(grq, "class", -1, "CCD"); + gctl_ro_param(grq, "unit", sizeof(ccd), &ccd); + gctl_ro_param(grq, "ileave", sizeof(ileave), &ileave); + if (flags & CCDF_UNIFORM) + gctl_ro_param(grq, "uniform", -1, ""); + if (flags & CCDF_MIRROR) + gctl_ro_param(grq, "mirror", -1, ""); + gctl_ro_param(grq, "nprovider", sizeof(argc), &argc); + for (i = 0; i < argc; i++) { + sprintf(buf1, "provider%d", i); + cp = argv[i]; + if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV))) + cp += strlen(_PATH_DEV); + gctl_ro_param(grq, buf1, -1, cp); } - for (i = 0; argc != 0; ) { - cp = *argv++; --argc; - if ((j = checkdev(cp)) == 0) - disks[i++] = cp; - else { - warnx("%s: %s", cp, strerror(j)); - return (1); + gctl_rw_param(grq, "output", sizeof(buf1), buf1); + errstr = gctl_issue(grq); + if (errstr == NULL) { + if (verbose) { + printf("%s", buf1); } + gctl_free(grq); + return (0); } - - /* Fill in the ccio. */ - ccio.ccio_disks = disks; - ccio.ccio_ndisks = i; - ccio.ccio_ileave = ileave; - ccio.ccio_flags = flags; - ccio.ccio_size = ccd; - - if (do_io(ccd, CCDIOCSET, &ccio)) { - free(disks); - return (1); - } - - if (verbose) { - printf("ccd%d: %d components ", ccio.ccio_unit, - ccio.ccio_ndisks); - for (u = 0; u < ccio.ccio_ndisks; ++u) { - if ((cp2 = strrchr(disks[u], '/')) != NULL) - ++cp2; - else - cp2 = disks[u]; - printf("%c%s%c", - u == 0 ? '(' : ' ', cp2, - u == ccio.ccio_ndisks - 1 ? ')' : ','); - } - printf(", %lu blocks ", (u_long)ccio.ccio_size); - if (ccio.ccio_ileave != 0) - printf("interleaved at %d blocks\n", ccio.ccio_ileave); - else - printf("concatenated\n"); - } - - free(disks); - return (0); + warnx( + "%s\nor possibly kernel and ccdconfig out of sync", + errstr); + return (1); } static int @@ -344,20 +332,6 @@ do_all(int action) return (rval); } -static int -checkdev(char *path) -{ - struct stat st; - - if (stat(path, &st) != 0) - return (errno); - - if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) - return (EINVAL); - - return (0); -} - static int resolve_ccdname(char *name) { @@ -372,48 +346,6 @@ resolve_ccdname(char *name) return (strtoul(name, NULL, 10)); } -static int -do_io(int unit, u_long cmd, struct ccd_ioctl *cciop) -{ - int fd; - char *cp; - char *path; - - asprintf(&path, "%s%s", _PATH_DEV, _PATH_CCDCTL); - - if ((fd = open(path, O_RDWR, 0640)) < 0) { - 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) { - switch (cmd) { - case CCDIOCSET: - cp = "CCDIOCSET"; - break; - - case CCDIOCCLR: - cp = "CCDIOCCLR"; - break; - - default: - cp = "unknown"; - } - warn("ioctl (%s): %s", cp, path); - return (1); - } - - return (0); -} - static int dumpout(int unit) { @@ -422,7 +354,6 @@ dumpout(int unit) int ncp; char *cp; char const *errstr; - grq = gctl_get_handle(); ncp = 65536; @@ -465,19 +396,18 @@ static int flags_to_val(char *flags) { char *cp, *tok; - int i, tmp, val = ~CCDF_USERMASK; + int i, tmp, val; size_t flagslen; - /* - * The most common case is that of NIL flags, so check for - * those first. - */ - if (strcmp("none", flags) == 0 || strcmp("0x0", flags) == 0 || - strcmp("0", flags) == 0) - return (0); + errno = 0; /* to check for ERANGE */ + val = (int)strtol(flags, &cp, 0); + if ((errno != ERANGE) && (*cp == '\0')) { + if (val & ~(CCDF_UNIFORM|CCDF_MIRROR)) + return (-1); + return (val); + } flagslen = strlen(flags); - /* Check for values represented by strings. */ if ((cp = strdup(flags)) == NULL) err(1, "no memory to parse flags"); @@ -488,35 +418,14 @@ flags_to_val(char *flags) break; if (flagvaltab[i].fv_flag == NULL) { free(cp); - goto bad_string; + return (-1); } tmp |= flagvaltab[i].fv_val; } /* If we get here, the string was ok. */ free(cp); - val = tmp; - goto out; - - bad_string: - - /* Check for values represented in hex. */ - if (flagslen > 2 && flags[0] == '0' && flags[1] == 'x') { - errno = 0; /* to check for ERANGE */ - val = (int)strtol(&flags[2], &cp, 16); - if ((errno == ERANGE) || (*cp != '\0')) - return (-1); - goto out; - } - - /* Check for values represented in decimal. */ - errno = 0; /* to check for ERANGE */ - val = (int)strtol(flags, &cp, 10); - if ((errno == ERANGE) || (*cp != '\0')) - return (-1); - - out: - return (((val & ~CCDF_USERMASK) == 0) ? val : -1); + return (tmp); } static void @@ -530,8 +439,3 @@ usage(void) " ccdconfig -g [ccd [...]]"); exit(1); } - -/* Local Variables: */ -/* c-argdecl-indent: 8 */ -/* c-indent-level: 8 */ -/* End: */ diff --git a/sys/conf/files b/sys/conf/files index 691caf43cfde..071aa88b9704 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -336,7 +336,6 @@ dev/buslogic/bt_mca.c optional bt mca dev/buslogic/bt_pci.c optional bt pci dev/cardbus/cardbus.c optional cardbus dev/cardbus/cardbus_cis.c optional cardbus -dev/ccd/ccd.c optional ccd dev/ciss/ciss.c optional ciss dev/cm/smc90cx6.c optional cm dev/cnw/if_cnw.c optional cnw card @@ -904,6 +903,8 @@ geom/geom_aes.c optional geom_aes geom/geom_apple.c optional geom_apple geom/geom_bsd.c optional geom_bsd geom/geom_bsd_enc.c optional geom_bsd +geom/geom_ccd.c optional ccd +geom/geom_ccd.c optional geom_ccd geom/geom_ctl.c standard geom/geom_dev.c standard geom/geom_disk.c standard diff --git a/sys/dev/ccd/ccd.c b/sys/dev/ccd/ccd.c deleted file mode 100644 index e358ff7f1bbc..000000000000 --- a/sys/dev/ccd/ccd.c +++ /dev/null @@ -1,1322 +0,0 @@ -/* - * Copyright (c) 2003 Poul-Henning Kamp. - * Copyright (c) 1995 Jason R. Thorpe. - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * All rights reserved. - * Copyright (c) 1988 University of Utah. - * - * This code is derived from software contributed to Berkeley by - * the Systems Programming Group of the University of Utah Computer - * Science Department. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project - * by Jason R. Thorpe. - * 4. The names of the authors may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * 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. - * - * Dynamic configuration and disklabel support by: - * Jason R. Thorpe - * Numerical Aerodynamic Simulation Facility - * Mail Stop 258-6 - * NASA Ames Research Center - * Moffett Field, CA 94035 - * - * from: Utah $Hdr: cd.c 1.6 90/11/28$ - * - * @(#)cd.c 8.2 (Berkeley) 11/16/93 - * - * $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ - * - * $FreeBSD$ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Component info table. - * Describes a single component of a concatenated disk. - */ -struct ccdcinfo { - struct vnode *ci_vp; /* device's vnode */ - dev_t ci_dev; /* XXX: device's dev_t */ - size_t ci_size; /* size */ - char *ci_path; /* path to component */ - size_t ci_pathlen; /* length of component path */ -}; - -/* - * Interleave description table. - * Computed at boot time to speed irregular-interleave lookups. - * The idea is that we interleave in "groups". First we interleave - * evenly over all component disks up to the size of the smallest - * component (the first group), then we interleave evenly over all - * remaining disks up to the size of the next-smallest (second group), - * and so on. - * - * Each table entry describes the interleave characteristics of one - * of these groups. For example if a concatenated disk consisted of - * three components of 5, 3, and 7 DEV_BSIZE blocks interleaved at - * DEV_BSIZE (1), the table would have three entries: - * - * ndisk startblk startoff dev - * 3 0 0 0, 1, 2 - * 2 9 3 0, 2 - * 1 13 5 2 - * 0 - - - - * - * which says that the first nine blocks (0-8) are interleaved over - * 3 disks (0, 1, 2) starting at block offset 0 on any component disk, - * the next 4 blocks (9-12) are interleaved over 2 disks (0, 2) starting - * at component block 3, and the remaining blocks (13-14) are on disk - * 2 starting at offset 5. - */ -struct ccdiinfo { - int ii_ndisk; /* # of disks range is interleaved over */ - daddr_t ii_startblk; /* starting scaled block # for range */ - daddr_t ii_startoff; /* starting component offset (block #) */ - int *ii_index; /* ordered list of components in range */ -}; - -/* - * Concatenated disk pseudo-geometry information. - */ -struct ccdgeom { - u_int32_t ccg_secsize; /* # bytes per sector */ - u_int32_t ccg_nsectors; /* # data sectors per track */ - u_int32_t ccg_ntracks; /* # tracks per cylinder */ - u_int32_t ccg_ncylinders; /* # cylinders per unit */ -}; - - -/* - * A concatenated disk is described by this structure. - */ -struct ccd_s { - LIST_ENTRY(ccd_s) list; - - int sc_unit; /* logical unit number */ - struct vnode **sc_vpp; /* array of component vnodes */ - int sc_flags; /* flags */ - int sc_cflags; /* configuration flags */ - size_t sc_size; /* size of ccd */ - int sc_ileave; /* interleave */ - u_int sc_nccdisks; /* number of components */ -#define CCD_MAXNDISKS 65536 - struct ccdcinfo *sc_cinfo; /* component info */ - struct ccdiinfo *sc_itable; /* interleave table */ - struct ccdgeom sc_geom; /* pseudo geometry info */ - int sc_pick; /* side of mirror picked */ - daddr_t sc_blk[2]; /* mirror localization */ - struct disk *sc_disk; - struct cdev *__remove00; /* XXX: remove when convenient */ -}; - -MALLOC_DEFINE(M_CCD, "CCD driver", "Concatenated Disk driver"); - -/* - This is how mirroring works (only writes are special): - - When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s - linked together by the cb_mirror field. "cb_pflags & - CCDPF_MIRROR_DONE" is set to 0 on both of them. - - When a component returns to ccdiodone(), it checks if "cb_pflags & - CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's - flag and returns. If it is, it means its partner has already - returned, so it will go to the regular cleanup. - - */ - -struct ccdbuf { - struct bio cb_buf; /* new I/O buf */ - struct bio *cb_obp; /* ptr. to original I/O buf */ - struct ccdbuf *cb_freenext; /* free list link */ - struct ccd_s *cb_softc; - int cb_comp; /* target component */ - int cb_pflags; /* mirror/parity status flag */ - struct ccdbuf *cb_mirror; /* mirror counterpart */ -}; - -/* bits in cb_pflags */ -#define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */ - -/* convinient macros for often-used statements */ -#define IS_ALLOCATED(unit) (ccdfind(unit) != NULL) -#define IS_INITED(cs) (((cs)->sc_flags & CCDF_INITED) != 0) - -static dev_t ccdctldev; - -static disk_strategy_t ccdstrategy; -static d_ioctl_t ccdctlioctl; - -#define NCCDFREEHIWAT 16 - -#define CDEV_MAJOR 74 - -static struct cdevsw ccdctl_cdevsw = { - .d_open = nullopen, - .d_close = nullclose, - .d_ioctl = ccdctlioctl, - .d_name = "ccdctl", - .d_maj = CDEV_MAJOR, -}; - -static LIST_HEAD(, ccd_s) ccd_softc_list = - LIST_HEAD_INITIALIZER(&ccd_softc_list); - -static struct ccd_s *ccdfind(int); -static struct ccd_s *ccdnew(int); -static int ccddestroy(struct ccd_s *); - -/* called during module initialization */ -static void ccdattach(void); -static int ccd_modevent(module_t, int, void *); - -/* called by biodone() at interrupt time */ -static void ccdiodone(struct bio *bp); - -static void ccdstart(struct ccd_s *, struct bio *); -static void ccdinterleave(struct ccd_s *, int); -static int ccdinit(struct ccd_s *, char **, struct thread *); -static int ccdlookup(char *, struct thread *p, struct vnode **); -static int ccdbuffer(struct ccdbuf **ret, struct ccd_s *, - struct bio *, daddr_t, caddr_t, long); -static int ccdlock(struct ccd_s *); -static void ccdunlock(struct ccd_s *); - - -/* - * Number of blocks to untouched in front of a component partition. - * This is to avoid violating its disklabel area when it starts at the - * beginning of the slice. - */ -#if !defined(CCD_OFFSET) -#define CCD_OFFSET 16 -#endif - -static struct ccd_s * -ccdfind(int unit) -{ - struct ccd_s *sc = NULL; - - /* XXX: LOCK(unique unit numbers) */ - LIST_FOREACH(sc, &ccd_softc_list, list) { - if (sc->sc_unit == unit) - break; - } - /* XXX: UNLOCK(unique unit numbers) */ - return ((sc == NULL) || (sc->sc_unit != unit) ? NULL : sc); -} - -static struct ccd_s * -ccdnew(int unit) -{ - struct ccd_s *sc; - - /* XXX: LOCK(unique unit numbers) */ - if (IS_ALLOCATED(unit) || unit > 32) - return (NULL); - - MALLOC(sc, struct ccd_s *, sizeof(*sc), M_CCD, M_WAITOK | M_ZERO); - sc->sc_unit = unit; - LIST_INSERT_HEAD(&ccd_softc_list, sc, list); - /* XXX: UNLOCK(unique unit numbers) */ - return (sc); -} - -static int -ccddestroy(struct ccd_s *sc) -{ - - /* XXX: LOCK(unique unit numbers) */ - LIST_REMOVE(sc, list); - /* XXX: UNLOCK(unique unit numbers) */ - FREE(sc, M_CCD); - return (0); -} - -/* - * Called by main() during pseudo-device attachment. All we need - * to do is to add devsw entries. - */ -static void -ccdattach() -{ - - ccdctldev = make_dev(&ccdctl_cdevsw, 0xffff00ff, - UID_ROOT, GID_OPERATOR, 0640, "ccd.ctl"); - ccdctldev->si_drv1 = ccdctldev; -} - -static int -ccd_modevent(module_t mod, int type, void *data) -{ - int error = 0; - - switch (type) { - case MOD_LOAD: - ccdattach(); - break; - - case MOD_UNLOAD: - printf("ccd0: Unload not supported!\n"); - error = EOPNOTSUPP; - break; - - case MOD_SHUTDOWN: - break; - - default: - error = EOPNOTSUPP; - } - return (error); -} - -DEV_MODULE(ccd, ccd_modevent, NULL); - -static int -ccdinit(struct ccd_s *cs, char **cpaths, struct thread *td) -{ - struct ccdcinfo *ci = NULL; /* XXX */ - size_t size; - int ix; - struct vnode *vp; - size_t minsize; - int maxsecsize; - struct ccdgeom *ccg = &cs->sc_geom; - char *tmppath = NULL; - int error = 0; - off_t mediasize; - u_int sectorsize; - - - cs->sc_size = 0; - - /* Allocate space for the component info. */ - cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), - M_CCD, M_WAITOK); - - /* - * Verify that each component piece exists and record - * relevant information about it. - */ - maxsecsize = 0; - minsize = 0; - tmppath = malloc(MAXPATHLEN, M_CCD, M_WAITOK); - for (ix = 0; ix < cs->sc_nccdisks; ix++) { - vp = cs->sc_vpp[ix]; - ci = &cs->sc_cinfo[ix]; - ci->ci_vp = vp; - - /* - * Copy in the pathname of the component. - */ - if ((error = copyinstr(cpaths[ix], tmppath, - MAXPATHLEN, &ci->ci_pathlen)) != 0) { - goto fail; - } - ci->ci_path = malloc(ci->ci_pathlen, M_CCD, M_WAITOK); - bcopy(tmppath, ci->ci_path, ci->ci_pathlen); - - ci->ci_dev = vn_todev(vp); - - /* - * Get partition information for the component. - */ - error = VOP_IOCTL(vp, DIOCGMEDIASIZE, (caddr_t)&mediasize, - FREAD, td->td_ucred, td); - if (error != 0) { - goto fail; - } - /* - * Get partition information for the component. - */ - error = VOP_IOCTL(vp, DIOCGSECTORSIZE, (caddr_t)§orsize, - FREAD, td->td_ucred, td); - if (error != 0) { - goto fail; - } - if (sectorsize > maxsecsize) - maxsecsize = sectorsize; - size = mediasize / DEV_BSIZE - CCD_OFFSET; - - /* - * Calculate the size, truncating to an interleave - * boundary if necessary. - */ - - if (cs->sc_ileave > 1) - size -= size % cs->sc_ileave; - - if (size == 0) { - error = ENODEV; - goto fail; - } - - if (minsize == 0 || size < minsize) - minsize = size; - ci->ci_size = size; - cs->sc_size += size; - } - - free(tmppath, M_CCD); - tmppath = NULL; - - /* - * Don't allow the interleave to be smaller than - * the biggest component sector. - */ - if ((cs->sc_ileave > 0) && - (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { - error = EINVAL; - goto fail; - } - - /* - * If uniform interleave is desired set all sizes to that of - * the smallest component. This will guarentee that a single - * interleave table is generated. - * - * Lost space must be taken into account when calculating the - * overall size. Half the space is lost when CCDF_MIRROR is - * specified. - */ - if (cs->sc_flags & CCDF_UNIFORM) { - for (ci = cs->sc_cinfo; - ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) { - ci->ci_size = minsize; - } - if (cs->sc_flags & CCDF_MIRROR) { - /* - * Check to see if an even number of components - * have been specified. The interleave must also - * be non-zero in order for us to be able to - * guarentee the topology. - */ - if (cs->sc_nccdisks % 2) { - printf("ccd%d: mirroring requires an even number of disks\n", cs->sc_unit ); - error = EINVAL; - goto fail; - } - if (cs->sc_ileave == 0) { - printf("ccd%d: an interleave must be specified when mirroring\n", cs->sc_unit); - error = EINVAL; - goto fail; - } - cs->sc_size = (cs->sc_nccdisks/2) * minsize; - } else { - if (cs->sc_ileave == 0) { - printf("ccd%d: an interleave must be specified when using parity\n", cs->sc_unit); - error = EINVAL; - goto fail; - } - cs->sc_size = cs->sc_nccdisks * minsize; - } - } - - /* - * Construct the interleave table. - */ - ccdinterleave(cs, cs->sc_unit); - - /* - * Create pseudo-geometry based on 1MB cylinders. It's - * pretty close. - */ - ccg->ccg_secsize = maxsecsize; - ccg->ccg_ntracks = 1; - ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize; - ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; - - cs->sc_flags |= CCDF_INITED; - cs->sc_cflags = cs->sc_flags; /* So we can find out later... */ - return (0); -fail: - while (ci > cs->sc_cinfo) { - ci--; - free(ci->ci_path, M_CCD); - } - if (tmppath != NULL) - free(tmppath, M_CCD); - free(cs->sc_cinfo, M_CCD); - ccddestroy(cs); - return (error); -} - -static void -ccdinterleave(struct ccd_s *cs, int unit) -{ - struct ccdcinfo *ci, *smallci; - struct ccdiinfo *ii; - daddr_t bn, lbn; - int ix; - u_long size; - - - /* - * Allocate an interleave table. The worst case occurs when each - * of N disks is of a different size, resulting in N interleave - * tables. - * - * Chances are this is too big, but we don't care. - */ - size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); - cs->sc_itable = (struct ccdiinfo *)malloc(size, M_CCD, - M_WAITOK | M_ZERO); - - /* - * 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 setup. - */ - if (cs->sc_ileave == 0) { - bn = 0; - ii = cs->sc_itable; - - for (ix = 0; ix < cs->sc_nccdisks; ix++) { - /* Allocate space for ii_index. */ - ii->ii_index = malloc(sizeof(int), M_CCD, M_WAITOK); - ii->ii_ndisk = 1; - ii->ii_startblk = bn; - ii->ii_startoff = 0; - ii->ii_index[0] = ix; - bn += cs->sc_cinfo[ix].ci_size; - ii++; - } - ii->ii_ndisk = 0; - return; - } - - /* - * The following isn't fast or pretty; it doesn't have to be. - */ - size = 0; - bn = lbn = 0; - for (ii = cs->sc_itable; ; ii++) { - /* - * Allocate space for ii_index. We might allocate more then - * we use. - */ - ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), - M_CCD, M_WAITOK); - - /* - * Locate the smallest of the remaining components - */ - smallci = NULL; - for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks]; - ci++) { - if (ci->ci_size > size && - (smallci == NULL || - ci->ci_size < smallci->ci_size)) { - smallci = ci; - } - } - - /* - * Nobody left, all done - */ - if (smallci == NULL) { - ii->ii_ndisk = 0; - free(ii->ii_index, M_CCD); - break; - } - - /* - * Record starting logical block using an sc_ileave blocksize. - */ - ii->ii_startblk = bn / cs->sc_ileave; - - /* - * Record starting comopnent block using an sc_ileave - * blocksize. This value is relative to the beginning of - * a component disk. - */ - ii->ii_startoff = lbn; - - /* - * Determine how many disks take part in this interleave - * and record their indices. - */ - ix = 0; - for (ci = cs->sc_cinfo; - ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) { - if (ci->ci_size >= smallci->ci_size) { - ii->ii_index[ix++] = ci - cs->sc_cinfo; - } - } - ii->ii_ndisk = ix; - bn += ix * (smallci->ci_size - size); - lbn = smallci->ci_size / cs->sc_ileave; - size = smallci->ci_size; - } -} - -static void -ccdstrategy(struct bio *bp) -{ - struct ccd_s *cs; - int pbn; /* in sc_secsize chunks */ - long sz; /* in sc_secsize chunks */ - - cs = bp->bio_disk->d_drv1; - - pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE); - sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize); - - /* - * If out of bounds return an error. If at the EOF point, - * simply read or write less. - */ - - if (pbn < 0 || pbn >= cs->sc_size) { - bp->bio_resid = bp->bio_bcount; - if (pbn != cs->sc_size) - biofinish(bp, NULL, EINVAL); - else - biodone(bp); - return; - } - - /* - * If the request crosses EOF, truncate the request. - */ - if (pbn + sz > cs->sc_size) { - bp->bio_bcount = (cs->sc_size - pbn) * - cs->sc_geom.ccg_secsize; - } - - bp->bio_resid = bp->bio_bcount; - - /* - * "Start" the unit. - */ - ccdstart(cs, bp); - return; -} - -static void -ccdstart(struct ccd_s *cs, struct bio *bp) -{ - long bcount, rcount; - struct ccdbuf *cbp[2]; - caddr_t addr; - daddr_t bn; - int err; - int sent; - - /* - * Translate the partition-relative block number to an absolute. - */ - bn = bp->bio_blkno; - - /* - * Allocate component buffers and fire off the requests - */ - addr = bp->bio_data; - sent = 0; - for (bcount = bp->bio_bcount; bcount > 0; bcount -= rcount) { - err = ccdbuffer(cbp, cs, bp, bn, addr, bcount); - if (err) { - printf("ccdbuffer error %d\n", err); - if (!sent) - biofinish(bp, NULL, err); - else { - /* - * XXX: maybe a race where the partners - * XXX: we sent already have been in - * XXX: ccdiodone(). Single-threaded g_down - * XXX: may protect against this. - */ - bp->bio_resid -= bcount; - bp->bio_error = err; - bp->bio_flags |= BIO_ERROR; - } - return; - } - rcount = cbp[0]->cb_buf.bio_bcount; - - if (cs->sc_cflags & CCDF_MIRROR) { - /* - * Mirroring. Writes go to both disks, reads are - * taken from whichever disk seems most appropriate. - * - * We attempt to localize reads to the disk whos arm - * is nearest the read request. We ignore seeks due - * to writes when making this determination and we - * also try to avoid hogging. - */ - if (cbp[0]->cb_buf.bio_cmd == BIO_WRITE) { - BIO_STRATEGY(&cbp[0]->cb_buf); - BIO_STRATEGY(&cbp[1]->cb_buf); - sent++; - } else { - int pick = cs->sc_pick; - daddr_t range = cs->sc_size / 16; - - if (bn < cs->sc_blk[pick] - range || - bn > cs->sc_blk[pick] + range - ) { - cs->sc_pick = pick = 1 - pick; - } - cs->sc_blk[pick] = bn + btodb(rcount); - BIO_STRATEGY(&cbp[pick]->cb_buf); - sent++; - } - } else { - /* - * Not mirroring - */ - BIO_STRATEGY(&cbp[0]->cb_buf); - sent++; - } - bn += btodb(rcount); - addr += rcount; - } -} - -/* - * Build a component buffer header. - */ -static int -ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, caddr_t addr, long bcount) -{ - struct ccdcinfo *ci, *ci2 = NULL; /* XXX */ - struct ccdbuf *cbp; - daddr_t cbn, cboff; - off_t cbc; - - /* - * Determine which component bn falls in. - */ - cbn = bn; - cboff = 0; - - if (cs->sc_ileave == 0) { - /* - * Serially concatenated and neither a mirror nor a parity - * config. This is a special case. - */ - daddr_t sblk; - - sblk = 0; - for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) - sblk += ci->ci_size; - cbn -= sblk; - } else { - struct ccdiinfo *ii; - int ccdisk, off; - - /* - * Calculate cbn, the logical superblock (sc_ileave chunks), - * and cboff, a normal block offset (DEV_BSIZE chunks) relative - * to cbn. - */ - cboff = cbn % cs->sc_ileave; /* DEV_BSIZE gran */ - cbn = cbn / cs->sc_ileave; /* DEV_BSIZE * ileave gran */ - - /* - * Figure out which interleave table to use. - */ - for (ii = cs->sc_itable; ii->ii_ndisk; ii++) { - if (ii->ii_startblk > cbn) - break; - } - ii--; - - /* - * off is the logical superblock relative to the beginning - * of this interleave block. - */ - off = cbn - ii->ii_startblk; - - /* - * We must calculate which disk component to use (ccdisk), - * and recalculate cbn to be the superblock relative to - * the beginning of the component. This is typically done by - * adding 'off' and ii->ii_startoff together. However, 'off' - * must typically be divided by the number of components in - * this interleave array to be properly convert it from a - * CCD-relative logical superblock number to a - * component-relative superblock number. - */ - if (ii->ii_ndisk == 1) { - /* - * When we have just one disk, it can't be a mirror - * or a parity config. - */ - ccdisk = ii->ii_index[0]; - cbn = ii->ii_startoff + off; - } else { - if (cs->sc_cflags & CCDF_MIRROR) { - /* - * We have forced a uniform mapping, resulting - * in a single interleave array. We double - * up on the first half of the available - * components and our mirror is in the second - * half. This only works with a single - * interleave array because doubling up - * doubles the number of sectors, so there - * cannot be another interleave array because - * the next interleave array's calculations - * would be off. - */ - int ndisk2 = ii->ii_ndisk / 2; - ccdisk = ii->ii_index[off % ndisk2]; - cbn = ii->ii_startoff + off / ndisk2; - ci2 = &cs->sc_cinfo[ccdisk + ndisk2]; - } else { - ccdisk = ii->ii_index[off % ii->ii_ndisk]; - cbn = ii->ii_startoff + off / ii->ii_ndisk; - } - } - - ci = &cs->sc_cinfo[ccdisk]; - - /* - * Convert cbn from a superblock to a normal block so it - * can be used to calculate (along with cboff) the normal - * block index into this particular disk. - */ - cbn *= cs->sc_ileave; - } - - /* - * Fill in the component buf structure. - */ - cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_NOWAIT | M_ZERO); - if (cbp == NULL) - return (ENOMEM); - cbp->cb_buf.bio_cmd = bp->bio_cmd; - cbp->cb_buf.bio_done = ccdiodone; - cbp->cb_buf.bio_dev = ci->ci_dev; /* XXX */ - cbp->cb_buf.bio_blkno = cbn + cboff + CCD_OFFSET; - cbp->cb_buf.bio_offset = dbtob(cbn + cboff + CCD_OFFSET); - cbp->cb_buf.bio_data = addr; - cbp->cb_buf.bio_caller2 = cbp; - if (cs->sc_ileave == 0) - cbc = dbtob((off_t)(ci->ci_size - cbn)); - else - cbc = dbtob((off_t)(cs->sc_ileave - cboff)); - cbp->cb_buf.bio_bcount = (cbc < bcount) ? cbc : bcount; - cbp->cb_buf.bio_caller1 = (void*)cbp->cb_buf.bio_bcount; - - /* - * context for ccdiodone - */ - cbp->cb_obp = bp; - cbp->cb_softc = cs; - cbp->cb_comp = ci - cs->sc_cinfo; - - cb[0] = cbp; - - /* - * Note: both I/O's setup when reading from mirror, but only one - * will be executed. - */ - if (cs->sc_cflags & CCDF_MIRROR) { - /* mirror, setup second I/O */ - cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_NOWAIT); - if (cbp == NULL) { - free(cb[0], M_CCD); - cb[0] = NULL; - return (ENOMEM); - } - bcopy(cb[0], cbp, sizeof(struct ccdbuf)); - cbp->cb_buf.bio_caller2 = cbp; - cbp->cb_buf.bio_dev = ci2->ci_dev; - cbp->cb_comp = ci2 - cs->sc_cinfo; - cb[1] = cbp; - /* link together the ccdbuf's and clear "mirror done" flag */ - cb[0]->cb_mirror = cb[1]; - cb[1]->cb_mirror = cb[0]; - cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; - cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; - } - return (0); -} - -/* - * Called at interrupt time. - * Mark the component as done and if all components are done, - * take a ccd interrupt. - */ -static void -ccdiodone(struct bio *ibp) -{ - struct ccdbuf *cbp; - struct bio *bp; - struct ccd_s *cs; - int count; - - cbp = ibp->bio_caller2; - cs = cbp->cb_softc; - bp = cbp->cb_obp; - /* - * If an error occured, report it. If this is a mirrored - * configuration and the first of two possible reads, do not - * set the error in the bp yet because the second read may - * succeed. - */ - - if (cbp->cb_buf.bio_flags & BIO_ERROR) { - const char *msg = ""; - - if ((cs->sc_cflags & CCDF_MIRROR) && - (cbp->cb_buf.bio_cmd == BIO_READ) && - (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { - /* - * We will try our read on the other disk down - * below, also reverse the default pick so if we - * are doing a scan we do not keep hitting the - * bad disk first. - */ - - msg = ", trying other disk"; - cs->sc_pick = 1 - cs->sc_pick; - cs->sc_blk[cs->sc_pick] = bp->bio_blkno; - } else { - bp->bio_flags |= BIO_ERROR; - bp->bio_error = cbp->cb_buf.bio_error ? - cbp->cb_buf.bio_error : EIO; - } - printf("ccd%d: error %d on component %d block %jd " - "(ccd block %jd)%s\n", cs->sc_unit, bp->bio_error, - cbp->cb_comp, - (intmax_t)cbp->cb_buf.bio_blkno, (intmax_t)bp->bio_blkno, - msg); - } - - /* - * Process mirror. If we are writing, I/O has been initiated on both - * buffers and we fall through only after both are finished. - * - * If we are reading only one I/O is initiated at a time. If an - * error occurs we initiate the second I/O and return, otherwise - * we free the second I/O without initiating it. - */ - - if (cs->sc_cflags & CCDF_MIRROR) { - if (cbp->cb_buf.bio_cmd == BIO_WRITE) { - /* - * When writing, handshake with the second buffer - * to determine when both are done. If both are not - * done, return here. - */ - if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { - cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; - free(cbp, M_CCD); - return; - } - } else { - /* - * When reading, either dispose of the second buffer - * or initiate I/O on the second buffer if an error - * occured with this one. - */ - if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { - if (cbp->cb_buf.bio_flags & BIO_ERROR) { - cbp->cb_mirror->cb_pflags |= - CCDPF_MIRROR_DONE; - BIO_STRATEGY(&cbp->cb_mirror->cb_buf); - free(cbp, M_CCD); - return; - } else { - free(cbp->cb_mirror, M_CCD); - } - } - } - } - - /* - * use bio_caller1 to determine how big the original request was rather - * then bio_bcount, because bio_bcount may have been truncated for EOF. - * - * XXX We check for an error, but we do not test the resid for an - * aligned EOF condition. This may result in character & block - * device access not recognizing EOF properly when read or written - * sequentially, but will not effect filesystems. - */ - count = (long)cbp->cb_buf.bio_caller1; - free(cbp, M_CCD); - - /* - * If all done, "interrupt". - */ - bp->bio_resid -= count; - if (bp->bio_resid < 0) - panic("ccdiodone: count"); - if (bp->bio_resid == 0) { - if (bp->bio_flags & BIO_ERROR) - bp->bio_resid = bp->bio_bcount; - biodone(bp); - } -} - -static int ccdioctltoo(int unit, u_long cmd, caddr_t data, int flag, struct thread *td); - -static int -ccdctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) -{ - struct ccd_ioctl *ccio; - u_int unit; - - switch (cmd) { - case CCDIOCSET: - case CCDIOCCLR: - ccio = (struct ccd_ioctl *)data; - unit = ccio->ccio_size; - return (ccdioctltoo(unit, cmd, data, flag, td)); - default: - return (ENOIOCTL); - } -} - -static int -ccdioctltoo(int unit, u_long cmd, caddr_t data, int flag, struct thread *td) -{ - int i, j, lookedup = 0, error = 0; - struct ccd_s *cs; - struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; - struct ccdgeom *ccg; - char **cpp; - struct vnode **vpp; - - cs = ccdfind(unit); - switch (cmd) { - case CCDIOCSET: - if (cs == NULL) - cs = ccdnew(unit); - if (IS_INITED(cs)) - return (EBUSY); - - if ((flag & FWRITE) == 0) - return (EBADF); - - if ((error = ccdlock(cs)) != 0) - return (error); - - if (ccio->ccio_ndisks > CCD_MAXNDISKS) - return (EINVAL); - - /* Fill in some important bits. */ - cs->sc_ileave = ccio->ccio_ileave; - if (cs->sc_ileave == 0 && (ccio->ccio_flags & CCDF_MIRROR)) { - printf("ccd%d: disabling mirror, interleave is 0\n", - unit); - ccio->ccio_flags &= ~(CCDF_MIRROR); - } - if ((ccio->ccio_flags & CCDF_MIRROR) && - !(ccio->ccio_flags & CCDF_UNIFORM)) { - printf("ccd%d: mirror/parity forces uniform flag\n", - unit); - ccio->ccio_flags |= CCDF_UNIFORM; - } - cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK; - - /* - * Allocate space for and copy in the array of - * componet pathnames and device numbers. - */ - cpp = malloc(ccio->ccio_ndisks * sizeof(char *), - M_CCD, M_WAITOK); - vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), - M_CCD, M_WAITOK); - - error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, - ccio->ccio_ndisks * sizeof(char **)); - if (error) { - free(vpp, M_CCD); - free(cpp, M_CCD); - ccdunlock(cs); - return (error); - } - - - for (i = 0; i < ccio->ccio_ndisks; ++i) { - if ((error = ccdlookup(cpp[i], td, &vpp[i])) != 0) { - for (j = 0; j < lookedup; ++j) - (void)vn_close(vpp[j], FREAD|FWRITE, - td->td_ucred, td); - free(vpp, M_CCD); - free(cpp, M_CCD); - ccdunlock(cs); - return (error); - } - ++lookedup; - } - cs->sc_vpp = vpp; - cs->sc_nccdisks = ccio->ccio_ndisks; - - /* - * Initialize the ccd. Fills in the softc for us. - */ - if ((error = ccdinit(cs, cpp, td)) != 0) { - for (j = 0; j < lookedup; ++j) - (void)vn_close(vpp[j], FREAD|FWRITE, - td->td_ucred, td); - /* - * We can't ccddestroy() cs just yet, because nothing - * prevents user-level app to do another ioctl() - * without closing the device first, therefore - * declare unit null and void and let ccdclose() - * destroy it when it is safe to do so. - */ - cs->sc_flags &= (CCDF_WANTED | CCDF_LOCKED); - free(vpp, M_CCD); - free(cpp, M_CCD); - ccdunlock(cs); - return (error); - } - free(cpp, M_CCD); - - /* - * The ccd has been successfully initialized, so - * we can place it into the array and read the disklabel. - */ - ccio->ccio_unit = unit; - ccio->ccio_size = cs->sc_size; - ccg = &cs->sc_geom; - cs->sc_disk = malloc(sizeof(struct disk), M_CCD, - M_ZERO | M_WAITOK); - cs->sc_disk->d_strategy = ccdstrategy; - cs->sc_disk->d_name = "ccd"; - cs->sc_disk->d_sectorsize = ccg->ccg_secsize; - cs->sc_disk->d_mediasize = - cs->sc_size * (off_t)ccg->ccg_secsize; - cs->sc_disk->d_fwsectors = ccg->ccg_nsectors; - cs->sc_disk->d_fwheads = ccg->ccg_ntracks; - cs->sc_disk->d_drv1 = cs; - cs->sc_disk->d_maxsize = MAXPHYS; - disk_create(unit, cs->sc_disk, 0, NULL, NULL); - - ccdunlock(cs); - - break; - - case CCDIOCCLR: - if (cs == NULL) - return (ENXIO); - - if (!IS_INITED(cs)) - return (ENXIO); - - if ((flag & FWRITE) == 0) - return (EBADF); - - if ((error = ccdlock(cs)) != 0) - return (error); - - /* Don't unconfigure if any other partitions are open */ - if (cs->sc_disk->d_flags & DISKFLAG_OPEN) { - ccdunlock(cs); - return (EBUSY); - } - - disk_destroy(cs->sc_disk); - free(cs->sc_disk, M_CCD); - cs->sc_disk = NULL; - /* Declare unit null and void (reset all flags) */ - cs->sc_flags &= (CCDF_WANTED | CCDF_LOCKED); - - /* Close the components and free their pathnames. */ - for (i = 0; i < cs->sc_nccdisks; ++i) { - /* - * XXX: this close could potentially fail and - * cause Bad Things. Maybe we need to force - * the close to happen? - */ - (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, - td->td_ucred, td); - free(cs->sc_cinfo[i].ci_path, M_CCD); - } - - /* Free interleave index. */ - for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) - free(cs->sc_itable[i].ii_index, M_CCD); - - /* Free component info and interleave table. */ - free(cs->sc_cinfo, M_CCD); - free(cs->sc_itable, M_CCD); - free(cs->sc_vpp, M_CCD); - - /* This must be atomic. */ - ccdunlock(cs); - ccddestroy(cs); - - break; - } - - return (0); -} - - -/* - * Lookup the provided name in the filesystem. If the file exists, - * is a valid block device, and isn't being used by anyone else, - * set *vpp to the file's vnode. - */ -static int -ccdlookup(char *path, struct thread *td, struct vnode **vpp) -{ - struct nameidata nd; - struct vnode *vp; - int error, flags; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, td); - flags = FREAD | FWRITE; - if ((error = vn_open(&nd, &flags, 0)) != 0) { - return (error); - } - vp = nd.ni_vp; - - if (vrefcnt(vp) > 1) { - error = EBUSY; - goto bad; - } - - if (!vn_isdisk(vp, &error)) - goto bad; - - - VOP_UNLOCK(vp, 0, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - *vpp = vp; - return (0); -bad: - VOP_UNLOCK(vp, 0, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - /* vn_close does vrele() for vp */ - (void)vn_close(vp, FREAD|FWRITE, td->td_ucred, td); - return (error); -} - -/* - - * Wait interruptibly for an exclusive lock. - * - * XXX - * Several drivers do this; it should be abstracted and made MP-safe. - */ -static int -ccdlock(struct ccd_s *cs) -{ - int error; - - while ((cs->sc_flags & CCDF_LOCKED) != 0) { - cs->sc_flags |= CCDF_WANTED; - if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) - return (error); - } - cs->sc_flags |= CCDF_LOCKED; - return (0); -} - -/* - * Unlock and wake up any waiters. - */ -static void -ccdunlock(struct ccd_s *cs) -{ - - cs->sc_flags &= ~CCDF_LOCKED; - if ((cs->sc_flags & CCDF_WANTED) != 0) { - cs->sc_flags &= ~CCDF_WANTED; - wakeup(cs); - } -} - -static struct sbuf * -g_ccd_list(int unit) -{ - struct sbuf *sb; - struct ccd_s *cs; - int i; - - sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); - sbuf_clear(sb); - LIST_FOREACH(cs, &ccd_softc_list, list) { - if (!IS_INITED(cs)) - continue; - if (unit >= 0 && unit != cs->sc_unit) - continue; - sbuf_printf(sb, "ccd%d\t\t%d\t%d\t", - cs->sc_unit, cs->sc_ileave, cs->sc_cflags & CCDF_USERMASK); - - for (i = 0; i < cs->sc_nccdisks; ++i) { - sbuf_printf(sb, "%s%s", i == 0 ? "" : " ", - cs->sc_cinfo[i].ci_path); - } - sbuf_printf(sb, "\n"); - } - sbuf_finish(sb); - return (sb); -} - -static void -g_ccd_config(struct gctl_req *req, struct g_class *mp, char const *verb) -{ - struct sbuf *sb; - int u, *up; - - g_topology_assert(); - if (!strcmp(verb, "create geom")) { - gctl_error(req, "TBD"); - } else if (!strcmp(verb, "destroy geom")) { - gctl_error(req, "TBD"); - } else if (!strcmp(verb, "list")) { - up = gctl_get_paraml(req, "unit", sizeof (int)); - u = *up; - sb = g_ccd_list(u); - gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); - } else { - gctl_error(req, "unknown verb"); - } -} - -static struct g_class g_ccd_class = { - .name = "CCD", - .ctlreq = g_ccd_config, -}; - -DECLARE_GEOM_CLASS(g_ccd_class, g_ccd); diff --git a/sys/sys/ccdvar.h b/sys/sys/ccdvar.h deleted file mode 100644 index f2f07fc87248..000000000000 --- a/sys/sys/ccdvar.h +++ /dev/null @@ -1,120 +0,0 @@ -/* $FreeBSD$ */ - -/* $NetBSD: ccdvar.h,v 1.7.2.1 1995/10/12 21:30:18 thorpej Exp $ */ - -/* - * Copyright (c) 1995 Jason R. Thorpe. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the NetBSD Project - * by Jason R. Thorpe. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * 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. - */ - -/* - * Copyright (c) 1988 University of Utah. - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Systems Programming Group of the University of Utah Computer - * Science Department. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, 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. - * - * from: Utah $Hdr: cdvar.h 1.1 90/07/09$ - * - * @(#)cdvar.h 8.1 (Berkeley) 6/10/93 - */ - -/* - * Dynamic configuration and disklabel support by: - * Jason R. Thorpe - * Numerical Aerodynamic Simulation Facility - * Mail Stop 258-6 - * NASA Ames Research Center - * Moffett Field, CA 94035 - */ - -/* - * This structure is used to configure a ccd via ioctl(2). - */ -struct ccd_ioctl { - char **ccio_disks; /* pointer to component paths */ - u_int ccio_ndisks; /* number of disks to concatenate */ - int ccio_ileave; /* interleave (DEV_BSIZE blocks) */ - int ccio_flags; /* misc. information */ - int ccio_unit; /* unit number: use varies */ - size_t ccio_size; /* (returned) size of ccd */ -}; - -/* sc_flags */ -#define CCDF_UNIFORM 0x02 /* use LCCD of sizes for uniform interleave */ -#define CCDF_MIRROR 0x04 /* use mirroring */ -#define CCDF_INITED 0x10 /* unit has been initialized */ -#define CCDF_WLABEL 0x20 /* label area is writable */ -#define CCDF_LABELLING 0x40 /* unit is currently being labelled */ -#define CCDF_WANTED 0x60 /* someone is waiting to obtain a lock */ -#define CCDF_LOCKED 0x80 /* unit is locked */ - -/* Mask of user-settable ccd flags. */ -#define CCDF_USERMASK (CCDF_UNIFORM|CCDF_MIRROR) - -/* - * Before you can use a unit, it must be configured with CCDIOCSET. - * The configuration persists across opens and closes of the device; - * a CCDIOCCLR must be used to reset a configuration. An attempt to - * CCDIOCSET an already active unit will return EBUSY. Attempts to - * CCDIOCCLR an inactive unit will return ENXIO. - */ -#define CCDIOCSET _IOWR('F', 16, struct ccd_ioctl) /* enable ccd */ -#define CCDIOCCLR _IOW('F', 17, struct ccd_ioctl) /* disable ccd */