Module Name: src Committed By: christos Date: Sat Apr 27 17:13:34 UTC 2013
Modified Files: src/sys/dev: ccd.c ccdvar.h Log Message: - no limit on the number of ccd devices. - provide sysctl for getting information. To generate a diff of this commit: cvs rdiff -u -r1.143 -r1.144 src/sys/dev/ccd.c cvs rdiff -u -r1.32 -r1.33 src/sys/dev/ccdvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ccd.c diff -u src/sys/dev/ccd.c:1.143 src/sys/dev/ccd.c:1.144 --- src/sys/dev/ccd.c:1.143 Sun Nov 13 18:02:46 2011 +++ src/sys/dev/ccd.c Sat Apr 27 13:13:32 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: ccd.c,v 1.143 2011/11/13 23:02:46 christos Exp $ */ +/* $NetBSD: ccd.c,v 1.144 2013/04/27 17:13:32 christos Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc. @@ -88,7 +88,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.143 2011/11/13 23:02:46 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.144 2013/04/27 17:13:32 christos Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -114,6 +114,7 @@ __KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.14 #include <sys/kauth.h> #include <sys/kthread.h> #include <sys/bufq.h> +#include <sys/sysctl.h> #include <uvm/uvm_extern.h> @@ -205,10 +206,70 @@ const struct cdevsw ccd_cdevsw = { static void printiinfo(struct ccdiinfo *); #endif -/* Publically visible for the benefit of libkvm and ccdconfig(8). */ -struct ccd_softc *ccd_softc; -const int ccd_softc_elemsize = sizeof(struct ccd_softc); -int numccd = 0; +static LIST_HEAD(, ccd_softc) ccds = LIST_HEAD_INITIALIZER(ccds); +static kmutex_t ccd_lock; + +static struct ccd_softc * +ccdcreate(int unit) { + struct ccd_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP); + if (sc == NULL) { +#ifdef DIAGNOSTIC + printf("%s: out of memory\n", __func__); +#endif + return NULL; + } + /* Initialize per-softc structures. */ + snprintf(sc->sc_xname, sizeof(sc->sc_xname), "ccd%d", unit); + mutex_init(&sc->sc_dvlock, MUTEX_DEFAULT, IPL_NONE); + sc->sc_iolock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); + cv_init(&sc->sc_stop, "ccdstop"); + cv_init(&sc->sc_push, "ccdthr"); + disk_init(&sc->sc_dkdev, sc->sc_xname, NULL); /* XXX */ + return sc; +} + +static void +ccddestroy(struct ccd_softc *sc) { + mutex_obj_free(sc->sc_iolock); + mutex_destroy(&sc->sc_dvlock); + cv_destroy(&sc->sc_stop); + cv_destroy(&sc->sc_push); + disk_destroy(&sc->sc_dkdev); + kmem_free(sc, sizeof(*sc)); +} + +static struct ccd_softc * +ccdget(int unit) { + struct ccd_softc *sc; + if (unit < 0) { +#ifdef DIAGNOSTIC + panic("%s: unit %d!", __func__, unit); +#endif + return NULL; + } + mutex_enter(&ccd_lock); + LIST_FOREACH(sc, &ccds, sc_link) { + if (sc->sc_unit == unit) { + mutex_exit(&ccd_lock); + return sc; + } + } + mutex_exit(&ccd_lock); + if ((sc = ccdcreate(unit)) == NULL) + return NULL; + mutex_enter(&ccd_lock); + LIST_INSERT_HEAD(&ccds, sc, sc_link); + mutex_exit(&ccd_lock); + return sc; +} + +static void +ccdput(struct ccd_softc *sc) { + mutex_enter(&ccd_lock); + LIST_REMOVE(sc, sc_link); + mutex_exit(&ccd_lock); + ccddestroy(sc); +} /* * Called by main() during pseudo-device attachment. All we need @@ -217,37 +278,11 @@ int numccd = 0; void ccdattach(int num) { - struct ccd_softc *cs; - int i; - - if (num <= 0) { -#ifdef DIAGNOSTIC - panic("ccdattach: count <= 0"); -#endif - return; - } - - ccd_softc = kmem_zalloc(num * ccd_softc_elemsize, KM_SLEEP); - if (ccd_softc == NULL) { - printf("WARNING: no memory for concatenated disks\n"); - return; - } - numccd = num; + mutex_init(&ccd_lock, MUTEX_DEFAULT, IPL_NONE); /* Initialize the component buffer pool. */ ccd_cache = pool_cache_init(sizeof(struct ccdbuf), 0, 0, 0, "ccdbuf", NULL, IPL_BIO, NULL, NULL, NULL); - - /* Initialize per-softc structures. */ - for (i = 0; i < num; i++) { - cs = &ccd_softc[i]; - snprintf(cs->sc_xname, sizeof(cs->sc_xname), "ccd%d", i); - mutex_init(&cs->sc_dvlock, MUTEX_DEFAULT, IPL_NONE); - cs->sc_iolock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); - cv_init(&cs->sc_stop, "ccdstop"); - cv_init(&cs->sc_push, "ccdthr"); - disk_init(&cs->sc_dkdev, cs->sc_xname, NULL); /* XXX */ - } } static int @@ -545,9 +580,8 @@ ccdopen(dev_t dev, int flags, int fmt, s if (ccddebug & CCDB_FOLLOW) printf("ccdopen(0x%"PRIx64", 0x%x)\n", dev, flags); #endif - if (unit >= numccd) - return (ENXIO); - cs = &ccd_softc[unit]; + if ((cs = ccdget(unit)) == NULL) + return ENXIO; mutex_enter(&cs->sc_dvlock); @@ -607,9 +641,8 @@ ccdclose(dev_t dev, int flags, int fmt, printf("ccdclose(0x%"PRIx64", 0x%x)\n", dev, flags); #endif - if (unit >= numccd) - return (ENXIO); - cs = &ccd_softc[unit]; + if ((cs = ccdget(unit)) == NULL) + return ENXIO; mutex_enter(&cs->sc_dvlock); @@ -690,7 +723,9 @@ static void ccdstrategy(struct buf *bp) { int unit = ccdunit(bp->b_dev); - struct ccd_softc *cs = &ccd_softc[unit]; + struct ccd_softc *cs; + if ((cs = ccdget(unit)) == NULL) + return; /* Must be open or reading label. */ KASSERT(cs->sc_dkdev.dk_openmask != 0 || @@ -975,9 +1010,8 @@ ccdread(dev_t dev, struct uio *uio, int if (ccddebug & CCDB_FOLLOW) printf("ccdread(0x%"PRIx64", %p)\n", dev, uio); #endif - if (unit >= numccd) - return (ENXIO); - cs = &ccd_softc[unit]; + if ((cs = ccdget(unit)) == NULL) + return 0; /* Unlocked advisory check, ccdstrategy check is synchronous. */ if ((cs->sc_flags & CCDF_INITED) == 0) @@ -997,9 +1031,8 @@ ccdwrite(dev_t dev, struct uio *uio, int if (ccddebug & CCDB_FOLLOW) printf("ccdwrite(0x%"PRIx64", %p)\n", dev, uio); #endif - if (unit >= numccd) - return (ENXIO); - cs = &ccd_softc[unit]; + if ((cs = ccdget(unit)) == NULL) + return ENOENT; /* Unlocked advisory check, ccdstrategy check is synchronous. */ if ((cs->sc_flags & CCDF_INITED) == 0) @@ -1024,9 +1057,8 @@ ccdioctl(dev_t dev, u_long cmd, void *da struct disklabel newlabel; #endif - if (unit >= numccd) - return (ENXIO); - cs = &ccd_softc[unit]; + if ((cs = ccdget(unit)) == NULL) + return ENOENT; uc = kauth_cred_get(); /* Must be open for writes for these commands... */ @@ -1238,6 +1270,7 @@ ccdioctl(dev_t dev, u_long cmd, void *da /* Detatch the disk. */ disk_detach(&cs->sc_dkdev); bufq_free(cs->sc_bufq); + ccdput(cs); break; case DIOCGDINFO: @@ -1359,9 +1392,8 @@ ccdsize(dev_t dev) int part, unit, omask, size; unit = ccdunit(dev); - if (unit >= numccd) - return (-1); - cs = &ccd_softc[unit]; + if ((cs = ccdget(unit)) == NULL) + return -1; if ((cs->sc_flags & CCDF_INITED) == 0) return (-1); @@ -1424,11 +1456,15 @@ static void ccdgetdisklabel(dev_t dev) { int unit = ccdunit(dev); - struct ccd_softc *cs = &ccd_softc[unit]; + struct ccd_softc *cs; const char *errstring; - struct disklabel *lp = cs->sc_dkdev.dk_label; - struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel; + struct disklabel *lp; + struct cpu_disklabel *clp; + if ((cs = ccdget(unit)) == NULL) + return; + lp = cs->sc_dkdev.dk_label; + clp = cs->sc_dkdev.dk_cpulabel; KASSERT(mutex_owned(&cs->sc_dvlock)); memset(clp, 0, sizeof(*clp)); @@ -1553,3 +1589,177 @@ ccd_modcmd(modcmd_t cmd, void *arg) return error; } + +static int +ccd_units_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct ccd_softc *sc; + int error, i, nccd, *units; + size_t size; + + nccd = 0; + mutex_enter(&ccd_lock); + LIST_FOREACH(sc, &ccds, sc_link) + nccd++; + mutex_exit(&ccd_lock); + + if (nccd != 0) { + size = nccd * sizeof(*units); + units = kmem_zalloc(size, KM_SLEEP); + if (units == NULL) + return ENOMEM; + + i = 0; + mutex_enter(&ccd_lock); + LIST_FOREACH(sc, &ccds, sc_link) { + if (i >= nccd) + break; + units[i] = sc->sc_unit; + } + mutex_exit(&ccd_lock); + } else { + units = NULL; + size = 0; + } + + node = *rnode; + node.sysctl_data = units; + node.sysctl_size = size; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (units) + kmem_free(units, size); + return error; +} + +static int +ccd_info_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct ccddiskinfo ccd; + struct ccd_softc *sc; + int unit; + + if (newp == NULL || newlen != sizeof(int)) + return EINVAL; + + unit = *(const int *)newp; + newp = NULL; + newlen = 0; + ccd.ccd_ndisks = ~0; + mutex_enter(&ccd_lock); + LIST_FOREACH(sc, &ccds, sc_link) { + if (sc->sc_unit == unit) { + ccd.ccd_ileave = sc->sc_ileave; + ccd.ccd_size = sc->sc_size; + ccd.ccd_ndisks = sc->sc_nccdisks; + ccd.ccd_flags = sc->sc_flags; + break; + } + } + mutex_exit(&ccd_lock); + + if (ccd.ccd_ndisks == ~0) + return ENOENT; + + node = *rnode; + node.sysctl_data = &ccd; + node.sysctl_size = sizeof(ccd); + + return sysctl_lookup(SYSCTLFN_CALL(&node)); +} + +static int +ccd_components_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + int error, unit; + size_t size; + char *names, *p, *ep; + struct ccd_softc *sc; + + if (newp == NULL || newlen != sizeof(int)) + return EINVAL; + + size = 0; + unit = *(const int *)newp; + newp = NULL; + newlen = 0; + mutex_enter(&ccd_lock); + LIST_FOREACH(sc, &ccds, sc_link) + if (sc->sc_unit == unit) { + for (size_t i = 0; i < sc->sc_nccdisks; i++) + size += strlen(sc->sc_cinfo[i].ci_path) + 1; + break; + } + mutex_exit(&ccd_lock); + + if (size == 0) + return ENOENT; + names = kmem_zalloc(size, KM_SLEEP); + if (names == NULL) + return ENOMEM; + + p = names; + ep = names + size; + mutex_enter(&ccd_lock); + LIST_FOREACH(sc, &ccds, sc_link) + if (sc->sc_unit == unit) { + for (size_t i = 0; i < sc->sc_nccdisks; i++) { + char *d = sc->sc_cinfo[i].ci_path; + while (p < ep && (*p++ = *d++) != '\0') + continue; + } + break; + } + mutex_exit(&ccd_lock); + + node = *rnode; + node.sysctl_data = names; + node.sysctl_size = ep - names; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + kmem_free(names, size); + return error; +} + +SYSCTL_SETUP(sysctl_kern_ccd_setup, "sysctl kern.ccd subtree setup") +{ + const struct sysctlnode *node = NULL; + + /* Make sure net.key exists before we register nodes underneath it. */ + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "kern", NULL, + NULL, 0, NULL, 0, + CTL_KERN, CTL_EOL); + sysctl_createv(clog, 0, NULL, &node, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "ccd", + SYSCTL_DESCR("ConCatenated Disk state"), + NULL, 0, NULL, 0, + CTL_KERN, CTL_CREATE, CTL_EOL); + + if (node == NULL) + return; + + sysctl_createv(clog, 0, &node, NULL, + CTLFLAG_PERMANENT | CTLFLAG_READONLY, + CTLTYPE_STRUCT, "units", + SYSCTL_DESCR("List of ccd unit numbers"), + ccd_units_sysctl, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, &node, NULL, + CTLFLAG_PERMANENT | CTLFLAG_READWRITE, + CTLTYPE_STRUCT, "info", + SYSCTL_DESCR("Information about a CCD unit"), + ccd_info_sysctl, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, &node, NULL, + CTLFLAG_PERMANENT | CTLFLAG_READWRITE, + CTLTYPE_STRUCT, "components", + SYSCTL_DESCR("Information about CCD components"), + ccd_components_sysctl, 0, NULL, 0, + CTL_CREATE, CTL_EOL); +} Index: src/sys/dev/ccdvar.h diff -u src/sys/dev/ccdvar.h:1.32 src/sys/dev/ccdvar.h:1.33 --- src/sys/dev/ccdvar.h:1.32 Tue Feb 8 15:20:26 2011 +++ src/sys/dev/ccdvar.h Sat Apr 27 13:13:34 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: ccdvar.h,v 1.32 2011/02/08 20:20:26 rmind Exp $ */ +/* $NetBSD: ccdvar.h,v 1.33 2013/04/27 17:13:34 christos Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc. @@ -158,6 +158,7 @@ struct ccdbuf; * A concatenated disk is described after initialization by this structure. */ struct ccd_softc { + int sc_unit; int sc_flags; /* flags */ size_t sc_size; /* size of ccd */ int sc_ileave; /* interleave */ @@ -169,14 +170,13 @@ struct ccd_softc { char sc_xname[8]; /* XXX external name */ struct disk sc_dkdev; /* generic disk device info */ kmutex_t sc_dvlock; /* lock on device node */ -#if defined(_KERNEL) /* XXX ccdconfig(8) refers softc directly using kvm */ struct bufq_state *sc_bufq; /* buffer queue */ kmutex_t *sc_iolock; /* lock on I/O start/stop */ kcondvar_t sc_stop; /* when inflight goes zero */ struct lwp *sc_thread; /* for deferred I/O */ kcondvar_t sc_push; /* for deferred I/O */ bool sc_zap; /* for deferred I/O */ -#endif + LIST_ENTRY(ccd_softc) sc_link; }; /* sc_flags */ @@ -203,4 +203,14 @@ struct ccd_softc { #define CCDIOCSET _IOWR('F', 16, struct ccd_ioctl) /* enable ccd */ #define CCDIOCCLR _IOW('F', 17, struct ccd_ioctl) /* disable ccd */ +/* + * Sysctl information + */ +struct ccddiskinfo { + int ccd_ileave; + u_int ccd_ndisks; + size_t ccd_size; + int ccd_flags; +}; + #endif /* _DEV_CCDVAR_H_ */