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_ */