The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ccd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ccd.c,v 1.189 2022/03/28 12:48:35 riastradh Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 1996, 1997, 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe, and by Andrew Doran.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright (c) 1988 University of Utah.
   34  * Copyright (c) 1990, 1993
   35  *      The Regents of the University of California.  All rights reserved.
   36  *
   37  * This code is derived from software contributed to Berkeley by
   38  * the Systems Programming Group of the University of Utah Computer
   39  * Science Department.
   40  *
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that the following conditions
   43  * are met:
   44  * 1. Redistributions of source code must retain the above copyright
   45  *    notice, this list of conditions and the following disclaimer.
   46  * 2. Redistributions in binary form must reproduce the above copyright
   47  *    notice, this list of conditions and the following disclaimer in the
   48  *    documentation and/or other materials provided with the distribution.
   49  * 3. Neither the name of the University nor the names of its contributors
   50  *    may be used to endorse or promote products derived from this software
   51  *    without specific prior written permission.
   52  *
   53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   63  * SUCH DAMAGE.
   64  *
   65  * from: Utah $Hdr: cd.c 1.6 90/11/28$
   66  *
   67  *      @(#)cd.c        8.2 (Berkeley) 11/16/93
   68  */
   69 
   70 /*
   71  * "Concatenated" disk driver.
   72  *
   73  * Notes on concurrency:
   74  *
   75  * => sc_dvlock serializes access to the device nodes, excluding block I/O.
   76  *
   77  * => sc_iolock serializes access to (sc_flags & CCDF_INITED), disk stats,
   78  *    sc_stop, sc_bufq and b_resid from master buffers.
   79  *
   80  * => a combination of CCDF_INITED, sc_inflight, and sc_iolock is used to
   81  *    serialize I/O and configuration changes.
   82  *
   83  * => the in-core disk label does not change while the device is open.
   84  *
   85  * On memory consumption: ccd fans out I/O requests and so needs to
   86  * allocate memory.  If the system is desperately low on memory, we
   87  * single thread I/O.
   88  */
   89 
   90 #include <sys/cdefs.h>
   91 __KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.189 2022/03/28 12:48:35 riastradh Exp $");
   92 
   93 #include <sys/param.h>
   94 #include <sys/systm.h>
   95 #include <sys/kernel.h>
   96 #include <sys/proc.h>
   97 #include <sys/errno.h>
   98 #include <sys/buf.h>
   99 #include <sys/kmem.h>
  100 #include <sys/pool.h>
  101 #include <sys/module.h>
  102 #include <sys/namei.h>
  103 #include <sys/stat.h>
  104 #include <sys/ioctl.h>
  105 #include <sys/disklabel.h>
  106 #include <sys/device.h>
  107 #include <sys/disk.h>
  108 #include <sys/syslog.h>
  109 #include <sys/fcntl.h>
  110 #include <sys/vnode.h>
  111 #include <sys/conf.h>
  112 #include <sys/mutex.h>
  113 #include <sys/queue.h>
  114 #include <sys/kauth.h>
  115 #include <sys/kthread.h>
  116 #include <sys/bufq.h>
  117 #include <sys/sysctl.h>
  118 #include <sys/compat_stub.h>
  119 
  120 #include <uvm/uvm_extern.h>
  121 
  122 #include <dev/ccdvar.h>
  123 #include <dev/dkvar.h>
  124 
  125 #include <miscfs/specfs/specdev.h> /* for v_rdev */
  126 
  127 #include "ioconf.h"
  128 
  129 #if defined(CCDDEBUG) && !defined(DEBUG)
  130 #define DEBUG
  131 #endif
  132 
  133 #ifdef DEBUG
  134 #define CCDB_FOLLOW     0x01
  135 #define CCDB_INIT       0x02
  136 #define CCDB_IO         0x04
  137 #define CCDB_LABEL      0x08
  138 #define CCDB_VNODE      0x10
  139 int ccddebug = 0x00;
  140 #endif
  141 
  142 #define ccdunit(x)      DISKUNIT(x)
  143 
  144 struct ccdbuf {
  145         struct buf      cb_buf;         /* new I/O buf */
  146         struct buf      *cb_obp;        /* ptr. to original I/O buf */
  147         struct ccd_softc *cb_sc;        /* pointer to ccd softc */
  148         int             cb_comp;        /* target component */
  149         SIMPLEQ_ENTRY(ccdbuf) cb_q;     /* fifo of component buffers */
  150 };
  151 
  152 /* component buffer pool */
  153 static pool_cache_t ccd_cache;
  154 
  155 #define CCD_GETBUF()            pool_cache_get(ccd_cache, PR_WAITOK)
  156 #define CCD_PUTBUF(cbp)         pool_cache_put(ccd_cache, cbp)
  157 
  158 #define CCDLABELDEV(dev)        \
  159         (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART))
  160 
  161 /* called by main() at boot time */
  162 void    ccddetach(void);
  163 
  164 /* called by biodone() at interrupt time */
  165 static void     ccdiodone(struct buf *);
  166 
  167 static void     ccdinterleave(struct ccd_softc *);
  168 static int      ccdinit(struct ccd_softc *, char **, struct vnode **,
  169                     struct lwp *);
  170 static struct ccdbuf *ccdbuffer(struct ccd_softc *, struct buf *,
  171                     daddr_t, void *, long);
  172 static void     ccdgetdefaultlabel(struct ccd_softc *, struct disklabel *);
  173 static void     ccdgetdisklabel(dev_t);
  174 static void     ccdmakedisklabel(struct ccd_softc *);
  175 static void     ccdstart(struct ccd_softc *);
  176 static void     ccdthread(void *);
  177 
  178 static dev_type_open(ccdopen);
  179 static dev_type_close(ccdclose);
  180 static dev_type_read(ccdread);
  181 static dev_type_write(ccdwrite);
  182 static dev_type_ioctl(ccdioctl);
  183 static dev_type_strategy(ccdstrategy);
  184 static dev_type_size(ccdsize);
  185 
  186 const struct bdevsw ccd_bdevsw = {
  187         .d_open = ccdopen,
  188         .d_close = ccdclose,
  189         .d_strategy = ccdstrategy,
  190         .d_ioctl = ccdioctl,
  191         .d_dump = nodump,
  192         .d_psize = ccdsize,
  193         .d_discard = nodiscard,
  194         .d_flag = D_DISK | D_MPSAFE
  195 };
  196 
  197 const struct cdevsw ccd_cdevsw = {
  198         .d_open = ccdopen,
  199         .d_close = ccdclose,
  200         .d_read = ccdread,
  201         .d_write = ccdwrite,
  202         .d_ioctl = ccdioctl,
  203         .d_stop = nostop,
  204         .d_tty = notty,
  205         .d_poll = nopoll,
  206         .d_mmap = nommap,
  207         .d_kqfilter = nokqfilter,
  208         .d_discard = nodiscard,
  209         .d_flag = D_DISK | D_MPSAFE
  210 };
  211 
  212 static const struct dkdriver ccddkdriver = {
  213         .d_strategy = ccdstrategy,
  214         .d_minphys = minphys
  215 }; 
  216 
  217 #ifdef DEBUG
  218 static  void printiinfo(struct ccdiinfo *);
  219 #endif
  220 
  221 static LIST_HEAD(, ccd_softc) ccds = LIST_HEAD_INITIALIZER(ccds);
  222 static kmutex_t ccd_lock;
  223 
  224 SYSCTL_SETUP_PROTO(sysctl_kern_ccd_setup);
  225 
  226 static struct ccd_softc *
  227 ccdcreate(int unit) {
  228         struct ccd_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
  229 
  230         /* Initialize per-softc structures. */
  231         snprintf(sc->sc_xname, sizeof(sc->sc_xname), "ccd%d", unit);
  232         sc->sc_unit = unit;
  233         mutex_init(&sc->sc_dvlock, MUTEX_DEFAULT, IPL_NONE);
  234         sc->sc_iolock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
  235         cv_init(&sc->sc_stop, "ccdstop");
  236         cv_init(&sc->sc_push, "ccdthr");
  237         disk_init(&sc->sc_dkdev, sc->sc_xname, &ccddkdriver);
  238         return sc;
  239 }
  240 
  241 static void
  242 ccddestroy(struct ccd_softc *sc) {
  243         mutex_obj_free(sc->sc_iolock);
  244         mutex_exit(&sc->sc_dvlock);
  245         mutex_destroy(&sc->sc_dvlock);
  246         cv_destroy(&sc->sc_stop);
  247         cv_destroy(&sc->sc_push);
  248         disk_destroy(&sc->sc_dkdev);
  249         kmem_free(sc, sizeof(*sc));
  250 }
  251 
  252 static struct ccd_softc *
  253 ccdget(int unit, int make) {
  254         struct ccd_softc *sc;
  255         if (unit < 0) {
  256 #ifdef DIAGNOSTIC
  257                 panic("%s: unit %d!", __func__, unit);
  258 #endif
  259                 return NULL;
  260         }
  261         mutex_enter(&ccd_lock);
  262         LIST_FOREACH(sc, &ccds, sc_link) {
  263                 if (sc->sc_unit == unit) {
  264                         mutex_exit(&ccd_lock);
  265                         return sc;
  266                 }
  267         }
  268         mutex_exit(&ccd_lock);
  269         if (!make)
  270                 return NULL;
  271         if ((sc = ccdcreate(unit)) == NULL)
  272                 return NULL;
  273         mutex_enter(&ccd_lock);
  274         LIST_INSERT_HEAD(&ccds, sc, sc_link);
  275         mutex_exit(&ccd_lock);
  276         return sc;
  277 }
  278 
  279 static void
  280 ccdput(struct ccd_softc *sc) {
  281         mutex_enter(&ccd_lock);
  282         LIST_REMOVE(sc, sc_link);
  283         mutex_exit(&ccd_lock);
  284         ccddestroy(sc);
  285 }
  286 
  287 /*
  288  * Called by main() during pseudo-device attachment.  All we need
  289  * to do is allocate enough space for devices to be configured later.
  290  */
  291 void
  292 ccdattach(int num)
  293 {
  294         mutex_init(&ccd_lock, MUTEX_DEFAULT, IPL_NONE);
  295 
  296         /* Initialize the component buffer pool. */
  297         ccd_cache = pool_cache_init(sizeof(struct ccdbuf), 0,
  298             0, 0, "ccdbuf", NULL, IPL_BIO, NULL, NULL, NULL);
  299 }
  300 
  301 void
  302 ccddetach(void)
  303 {
  304         pool_cache_destroy(ccd_cache);
  305         mutex_destroy(&ccd_lock);
  306 }
  307 
  308 static int
  309 ccdinit(struct ccd_softc *cs, char **cpaths, struct vnode **vpp,
  310     struct lwp *l)
  311 {
  312         struct ccdcinfo *ci = NULL;
  313         int ix;
  314         struct ccdgeom *ccg = &cs->sc_geom;
  315         char *tmppath;
  316         int error, path_alloced;
  317         uint64_t psize, minsize;
  318         unsigned secsize, maxsecsize;
  319         struct disk_geom *dg;
  320 
  321 #ifdef DEBUG
  322         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
  323                 printf("%s: ccdinit\n", cs->sc_xname);
  324 #endif
  325 
  326         /* Allocate space for the component info. */
  327         cs->sc_cinfo = kmem_alloc(cs->sc_nccdisks * sizeof(*cs->sc_cinfo),
  328             KM_SLEEP);
  329         tmppath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
  330 
  331         cs->sc_size = 0;
  332 
  333         /*
  334          * Verify that each component piece exists and record
  335          * relevant information about it.
  336          */
  337         maxsecsize = 0;
  338         minsize = 0;
  339         for (ix = 0, path_alloced = 0; ix < cs->sc_nccdisks; ix++) {
  340                 ci = &cs->sc_cinfo[ix];
  341                 ci->ci_vp = vpp[ix];
  342 
  343                 /*
  344                  * Copy in the pathname of the component.
  345                  */
  346                 memset(tmppath, 0, MAXPATHLEN); /* sanity */
  347                 error = copyinstr(cpaths[ix], tmppath,
  348                     MAXPATHLEN, &ci->ci_pathlen);
  349                 if (ci->ci_pathlen == 0)
  350                         error = EINVAL;
  351                 if (error) {
  352 #ifdef DEBUG
  353                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
  354                                 printf("%s: can't copy path, error = %d\n",
  355                                     cs->sc_xname, error);
  356 #endif
  357                         goto out;
  358                 }
  359                 ci->ci_path = kmem_alloc(ci->ci_pathlen, KM_SLEEP);
  360                 memcpy(ci->ci_path, tmppath, ci->ci_pathlen);
  361                 path_alloced++;
  362 
  363                 /*
  364                  * XXX: Cache the component's dev_t.
  365                  */
  366                 ci->ci_dev = vpp[ix]->v_rdev;
  367 
  368                 /*
  369                  * Get partition information for the component.
  370                  */
  371                 error = getdisksize(vpp[ix], &psize, &secsize);
  372                 if (error) {
  373 #ifdef DEBUG
  374                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
  375                                  printf("%s: %s: disksize failed, error = %d\n",
  376                                      cs->sc_xname, ci->ci_path, error);
  377 #endif
  378                         goto out;
  379                 }
  380 
  381                 /*
  382                  * Calculate the size, truncating to an interleave
  383                  * boundary if necessary.
  384                  */
  385                 maxsecsize = secsize > maxsecsize ? secsize : maxsecsize;
  386                 if (cs->sc_ileave > 1)
  387                         psize -= psize % cs->sc_ileave;
  388 
  389                 if (psize == 0) {
  390 #ifdef DEBUG
  391                         if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
  392                                 printf("%s: %s: size == 0\n",
  393                                     cs->sc_xname, ci->ci_path);
  394 #endif
  395                         error = ENODEV;
  396                         goto out;
  397                 }
  398 
  399                 if (minsize == 0 || psize < minsize)
  400                         minsize = psize;
  401                 ci->ci_size = psize;
  402                 cs->sc_size += psize;
  403         }
  404 
  405         /*
  406          * Don't allow the interleave to be smaller than
  407          * the biggest component sector.
  408          */
  409         if ((cs->sc_ileave > 0) &&
  410             (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
  411 #ifdef DEBUG
  412                 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
  413                         printf("%s: interleave must be at least %d\n",
  414                             cs->sc_xname, (maxsecsize / DEV_BSIZE));
  415 #endif
  416                 error = EINVAL;
  417                 goto out;
  418         }
  419 
  420         /*
  421          * If uniform interleave is desired set all sizes to that of
  422          * the smallest component.
  423          */
  424         if (cs->sc_flags & CCDF_UNIFORM) {
  425                 for (ci = cs->sc_cinfo;
  426                      ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
  427                         ci->ci_size = minsize;
  428 
  429                 cs->sc_size = cs->sc_nccdisks * minsize;
  430         }
  431 
  432         /*
  433          * Construct the interleave table.
  434          */
  435         ccdinterleave(cs);
  436 
  437         /*
  438          * Create pseudo-geometry based on 1MB cylinders.  It's
  439          * pretty close.
  440          */
  441         ccg->ccg_secsize = DEV_BSIZE;
  442         ccg->ccg_ntracks = 1;
  443         ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
  444         ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
  445 
  446         dg = &cs->sc_dkdev.dk_geom;
  447         memset(dg, 0, sizeof(*dg));
  448         dg->dg_secperunit = cs->sc_size;
  449         dg->dg_secsize = ccg->ccg_secsize;
  450         dg->dg_nsectors = ccg->ccg_nsectors;
  451         dg->dg_ntracks = ccg->ccg_ntracks;
  452         dg->dg_ncylinders = ccg->ccg_ncylinders;
  453 
  454         if (cs->sc_ileave > 0)
  455                 aprint_normal("%s: Interleaving %d component%s "
  456                     "(%d block interleave)\n", cs->sc_xname,
  457                     cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : ""),
  458                     cs->sc_ileave);
  459         else
  460                 aprint_normal("%s: Concatenating %d component%s\n",
  461                     cs->sc_xname,
  462                     cs->sc_nccdisks, (cs->sc_nccdisks != 0 ? "s" : ""));
  463         for (ix = 0; ix < cs->sc_nccdisks; ix++) {
  464                 ci = &cs->sc_cinfo[ix];
  465                 aprint_normal("%s: %s (%ju blocks)\n", cs->sc_xname,
  466                     ci->ci_path, (uintmax_t)ci->ci_size);
  467         }
  468         aprint_normal("%s: total %ju blocks\n", cs->sc_xname, cs->sc_size);
  469 
  470         /*
  471          * Create thread to handle deferred I/O.
  472          */
  473         cs->sc_zap = false;
  474         error = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, ccdthread,
  475             cs, &cs->sc_thread, "%s", cs->sc_xname);
  476         if (error) {
  477                 printf("ccdinit: can't create thread: %d\n", error);
  478                 goto out;
  479         }
  480 
  481         /*
  482          * Only now that everything is set up can we enable the device.
  483          */
  484         mutex_enter(cs->sc_iolock);
  485         cs->sc_flags |= CCDF_INITED;
  486         mutex_exit(cs->sc_iolock);
  487         kmem_free(tmppath, MAXPATHLEN);
  488         return (0);
  489 
  490  out:
  491         for (ix = 0; ix < path_alloced; ix++) {
  492                 kmem_free(cs->sc_cinfo[ix].ci_path,
  493                     cs->sc_cinfo[ix].ci_pathlen);
  494         }
  495         kmem_free(cs->sc_cinfo, cs->sc_nccdisks * sizeof(struct ccdcinfo));
  496         kmem_free(tmppath, MAXPATHLEN);
  497         return (error);
  498 }
  499 
  500 static void
  501 ccdinterleave(struct ccd_softc *cs)
  502 {
  503         struct ccdcinfo *ci, *smallci;
  504         struct ccdiinfo *ii;
  505         daddr_t bn, lbn;
  506         int ix;
  507         u_long size;
  508 
  509 #ifdef DEBUG
  510         if (ccddebug & CCDB_INIT)
  511                 printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
  512 #endif
  513         /*
  514          * Allocate an interleave table.
  515          * Chances are this is too big, but we don't care.
  516          */
  517         size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
  518         cs->sc_itable = kmem_zalloc(size, KM_SLEEP);
  519 
  520         /*
  521          * Trivial case: no interleave (actually interleave of disk size).
  522          * Each table entry represents a single component in its entirety.
  523          */
  524         if (cs->sc_ileave == 0) {
  525                 bn = 0;
  526                 ii = cs->sc_itable;
  527 
  528                 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
  529                         /* Allocate space for ii_index. */
  530                         ii->ii_indexsz = sizeof(int);
  531                         ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP);
  532                         ii->ii_ndisk = 1;
  533                         ii->ii_startblk = bn;
  534                         ii->ii_startoff = 0;
  535                         ii->ii_index[0] = ix;
  536                         bn += cs->sc_cinfo[ix].ci_size;
  537                         ii++;
  538                 }
  539                 ii->ii_ndisk = 0;
  540 #ifdef DEBUG
  541                 if (ccddebug & CCDB_INIT)
  542                         printiinfo(cs->sc_itable);
  543 #endif
  544                 return;
  545         }
  546 
  547         /*
  548          * The following isn't fast or pretty; it doesn't have to be.
  549          */
  550         size = 0;
  551         bn = lbn = 0;
  552         for (ii = cs->sc_itable; ; ii++) {
  553                 /* Allocate space for ii_index. */
  554                 ii->ii_indexsz = sizeof(int) * cs->sc_nccdisks;
  555                 ii->ii_index = kmem_alloc(ii->ii_indexsz, KM_SLEEP);
  556 
  557                 /*
  558                  * Locate the smallest of the remaining components
  559                  */
  560                 smallci = NULL;
  561                 for (ci = cs->sc_cinfo;
  562                      ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
  563                         if (ci->ci_size > size &&
  564                             (smallci == NULL ||
  565                              ci->ci_size < smallci->ci_size))
  566                                 smallci = ci;
  567 
  568                 /*
  569                  * Nobody left, all done
  570                  */
  571                 if (smallci == NULL) {
  572                         ii->ii_ndisk = 0;
  573                         break;
  574                 }
  575 
  576                 /*
  577                  * Record starting logical block and component offset
  578                  */
  579                 ii->ii_startblk = bn / cs->sc_ileave;
  580                 ii->ii_startoff = lbn;
  581 
  582                 /*
  583                  * Determine how many disks take part in this interleave
  584                  * and record their indices.
  585                  */
  586                 ix = 0;
  587                 for (ci = cs->sc_cinfo;
  588                      ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
  589                         if (ci->ci_size >= smallci->ci_size)
  590                                 ii->ii_index[ix++] = ci - cs->sc_cinfo;
  591                 ii->ii_ndisk = ix;
  592                 bn += ix * (smallci->ci_size - size);
  593                 lbn = smallci->ci_size / cs->sc_ileave;
  594                 size = smallci->ci_size;
  595         }
  596 #ifdef DEBUG
  597         if (ccddebug & CCDB_INIT)
  598                 printiinfo(cs->sc_itable);
  599 #endif
  600 }
  601 
  602 /* ARGSUSED */
  603 static int
  604 ccdopen(dev_t dev, int flags, int fmt, struct lwp *l)
  605 {
  606         int unit = ccdunit(dev);
  607         struct ccd_softc *cs;
  608         struct disklabel *lp;
  609         int error = 0, part, pmask;
  610 
  611 #ifdef DEBUG
  612         if (ccddebug & CCDB_FOLLOW)
  613                 printf("ccdopen(0x%"PRIx64", 0x%x)\n", dev, flags);
  614 #endif
  615         if ((cs = ccdget(unit, 1)) == NULL)
  616                 return ENXIO;
  617 
  618         mutex_enter(&cs->sc_dvlock);
  619 
  620         lp = cs->sc_dkdev.dk_label;
  621 
  622         part = DISKPART(dev);
  623         pmask = (1 << part);
  624 
  625         /*
  626          * If we're initialized, check to see if there are any other
  627          * open partitions.  If not, then it's safe to update
  628          * the in-core disklabel.  Only read the disklabel if it is
  629          * not already valid.
  630          */
  631         if ((cs->sc_flags & (CCDF_INITED|CCDF_VLABEL)) == CCDF_INITED &&
  632             cs->sc_dkdev.dk_openmask == 0)
  633                 ccdgetdisklabel(dev);
  634 
  635         /* Check that the partition exists. */
  636         if (part != RAW_PART) {
  637                 if (((cs->sc_flags & CCDF_INITED) == 0) ||
  638                     ((part >= lp->d_npartitions) ||
  639                      (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
  640                         error = ENXIO;
  641                         goto done;
  642                 }
  643         }
  644 
  645         /* Prevent our unit from being unconfigured while open. */
  646         switch (fmt) {
  647         case S_IFCHR:
  648                 cs->sc_dkdev.dk_copenmask |= pmask;
  649                 break;
  650 
  651         case S_IFBLK:
  652                 cs->sc_dkdev.dk_bopenmask |= pmask;
  653                 break;
  654         }
  655         cs->sc_dkdev.dk_openmask =
  656             cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
  657 
  658  done:
  659         mutex_exit(&cs->sc_dvlock);
  660         return (error);
  661 }
  662 
  663 /* ARGSUSED */
  664 static int
  665 ccdclose(dev_t dev, int flags, int fmt, struct lwp *l)
  666 {
  667         int unit = ccdunit(dev);
  668         struct ccd_softc *cs;
  669         int part;
  670 
  671 #ifdef DEBUG
  672         if (ccddebug & CCDB_FOLLOW)
  673                 printf("ccdclose(0x%"PRIx64", 0x%x)\n", dev, flags);
  674 #endif
  675 
  676         if ((cs = ccdget(unit, 0)) == NULL)
  677                 return ENXIO;
  678 
  679         mutex_enter(&cs->sc_dvlock);
  680 
  681         part = DISKPART(dev);
  682 
  683         /* ...that much closer to allowing unconfiguration... */
  684         switch (fmt) {
  685         case S_IFCHR:
  686                 cs->sc_dkdev.dk_copenmask &= ~(1 << part);
  687                 break;
  688 
  689         case S_IFBLK:
  690                 cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
  691                 break;
  692         }
  693         cs->sc_dkdev.dk_openmask =
  694             cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
  695 
  696         if (cs->sc_dkdev.dk_openmask == 0) {
  697                 if ((cs->sc_flags & CCDF_KLABEL) == 0)
  698                         cs->sc_flags &= ~CCDF_VLABEL;
  699         }
  700 
  701         mutex_exit(&cs->sc_dvlock);
  702         return (0);
  703 }
  704 
  705 static bool
  706 ccdbackoff(struct ccd_softc *cs)
  707 {
  708 
  709         /* XXX Arbitrary, should be a uvm call. */
  710         return uvm_availmem(true) < (uvmexp.freemin >> 1) &&
  711             disk_isbusy(&cs->sc_dkdev);
  712 }
  713 
  714 static void
  715 ccdthread(void *cookie)
  716 {
  717         struct ccd_softc *cs;
  718 
  719         cs = cookie;
  720 
  721 #ifdef DEBUG
  722         if (ccddebug & CCDB_FOLLOW)
  723                 printf("ccdthread: hello\n");
  724 #endif
  725 
  726         mutex_enter(cs->sc_iolock);
  727         while (__predict_true(!cs->sc_zap)) {
  728                 if (bufq_peek(cs->sc_bufq) == NULL) {
  729                         /* Nothing to do. */
  730                         cv_wait(&cs->sc_push, cs->sc_iolock);
  731                         continue;
  732                 }
  733                 if (ccdbackoff(cs)) {
  734                         /* Wait for memory to become available. */
  735                         (void)cv_timedwait(&cs->sc_push, cs->sc_iolock, 1);
  736                         continue;
  737                 }
  738 #ifdef DEBUG
  739                 if (ccddebug & CCDB_FOLLOW)
  740                         printf("ccdthread: dispatching I/O\n");
  741 #endif
  742                 ccdstart(cs);
  743                 mutex_enter(cs->sc_iolock);
  744         }
  745         cs->sc_thread = NULL;
  746         mutex_exit(cs->sc_iolock);
  747 #ifdef DEBUG
  748         if (ccddebug & CCDB_FOLLOW)
  749                 printf("ccdthread: goodbye\n");
  750 #endif
  751         kthread_exit(0);
  752 }
  753 
  754 static void
  755 ccdstrategy(struct buf *bp)
  756 {
  757         int unit = ccdunit(bp->b_dev);
  758         struct ccd_softc *cs;
  759         if ((cs = ccdget(unit, 0)) == NULL)
  760                 return;
  761 
  762         /* Must be open or reading label. */
  763         KASSERT(cs->sc_dkdev.dk_openmask != 0 ||
  764             (cs->sc_flags & CCDF_RLABEL) != 0);
  765 
  766         mutex_enter(cs->sc_iolock);
  767         /* Synchronize with device init/uninit. */
  768         if (__predict_false((cs->sc_flags & CCDF_INITED) == 0)) {
  769                 mutex_exit(cs->sc_iolock);
  770 #ifdef DEBUG
  771                 if (ccddebug & CCDB_FOLLOW)
  772                         printf("ccdstrategy: unit %d: not inited\n", unit);
  773 #endif
  774                 bp->b_error = ENXIO;
  775                 bp->b_resid = bp->b_bcount;
  776                 biodone(bp);
  777                 return;
  778         }
  779 
  780         /* Defer to thread if system is low on memory. */
  781         bufq_put(cs->sc_bufq, bp);
  782         if (__predict_false(ccdbackoff(cs))) {
  783                 mutex_exit(cs->sc_iolock);
  784 #ifdef DEBUG
  785                 if (ccddebug & CCDB_FOLLOW)
  786                         printf("ccdstrategy: holding off on I/O\n");
  787 #endif
  788                 return;
  789         }
  790         ccdstart(cs);
  791 }
  792 
  793 static void
  794 ccdstart(struct ccd_softc *cs)
  795 {
  796         daddr_t blkno;
  797         int wlabel;
  798         struct disklabel *lp;
  799         long bcount, rcount;
  800         struct ccdbuf *cbp;
  801         char *addr;
  802         daddr_t bn;
  803         vnode_t *vp;
  804         buf_t *bp;
  805 
  806         KASSERT(mutex_owned(cs->sc_iolock));
  807 
  808         bp = bufq_get(cs->sc_bufq);
  809         KASSERT(bp != NULL);
  810 
  811         disk_busy(&cs->sc_dkdev);
  812 
  813 #ifdef DEBUG
  814         if (ccddebug & CCDB_FOLLOW)
  815                 printf("ccdstart(%s, %p)\n", cs->sc_xname, bp);
  816 #endif
  817 
  818         /* If it's a nil transfer, wake up the top half now. */
  819         if (bp->b_bcount == 0)
  820                 goto done;
  821 
  822         lp = cs->sc_dkdev.dk_label;
  823 
  824         /*
  825          * Do bounds checking and adjust transfer.  If there's an
  826          * error, the bounds check will flag that for us.  Convert
  827          * the partition relative block number to an absolute.
  828          */
  829         blkno = bp->b_blkno;
  830         wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
  831         if (DISKPART(bp->b_dev) != RAW_PART) {
  832                 if (bounds_check_with_label(&cs->sc_dkdev, bp, wlabel) <= 0)
  833                         goto done;
  834                 blkno += lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
  835         }
  836         mutex_exit(cs->sc_iolock);
  837         bp->b_rawblkno = blkno;
  838 
  839         /* Allocate the component buffers and start I/O! */
  840         bp->b_resid = bp->b_bcount;
  841         bn = bp->b_rawblkno;
  842         addr = bp->b_data;
  843         for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
  844                 cbp = ccdbuffer(cs, bp, bn, addr, bcount);
  845                 rcount = cbp->cb_buf.b_bcount;
  846                 bn += btodb(rcount);
  847                 addr += rcount;
  848                 vp = cbp->cb_buf.b_vp;
  849                 if ((cbp->cb_buf.b_flags & B_READ) == 0) {
  850                         mutex_enter(vp->v_interlock);
  851                         vp->v_numoutput++;
  852                         mutex_exit(vp->v_interlock);
  853                 }
  854                 (void)VOP_STRATEGY(vp, &cbp->cb_buf);
  855         }
  856         return;
  857 
  858  done:
  859         disk_unbusy(&cs->sc_dkdev, 0, 0);
  860         cv_broadcast(&cs->sc_stop);
  861         cv_broadcast(&cs->sc_push);
  862         mutex_exit(cs->sc_iolock);
  863         bp->b_resid = bp->b_bcount;
  864         biodone(bp);
  865 }
  866 
  867 /*
  868  * Build a component buffer header.
  869  */
  870 static struct ccdbuf *
  871 ccdbuffer(struct ccd_softc *cs, struct buf *bp, daddr_t bn, void *addr,
  872     long bcount)
  873 {
  874         struct ccdcinfo *ci;
  875         struct ccdbuf *cbp;
  876         daddr_t cbn, cboff;
  877         u_int64_t cbc;
  878         int ccdisk;
  879 
  880 #ifdef DEBUG
  881         if (ccddebug & CCDB_IO)
  882                 printf("ccdbuffer(%p, %p, %" PRId64 ", %p, %ld)\n",
  883                        cs, bp, bn, addr, bcount);
  884 #endif
  885         /*
  886          * Determine which component bn falls in.
  887          */
  888         cbn = bn;
  889         cboff = 0;
  890 
  891         /*
  892          * Serially concatenated
  893          */
  894         if (cs->sc_ileave == 0) {
  895                 daddr_t sblk;
  896 
  897                 sblk = 0;
  898                 for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
  899                     cbn >= sblk + ci->ci_size;
  900                     ccdisk++, ci = &cs->sc_cinfo[ccdisk])
  901                         sblk += ci->ci_size;
  902                 cbn -= sblk;
  903         }
  904         /*
  905          * Interleaved
  906          */
  907         else {
  908                 struct ccdiinfo *ii;
  909                 int off;
  910 
  911                 cboff = cbn % cs->sc_ileave;
  912                 cbn /= cs->sc_ileave;
  913                 for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
  914                         if (ii->ii_startblk > cbn)
  915                                 break;
  916                 ii--;
  917                 off = cbn - ii->ii_startblk;
  918                 if (ii->ii_ndisk == 1) {
  919                         ccdisk = ii->ii_index[0];
  920                         cbn = ii->ii_startoff + off;
  921                 } else {
  922                         ccdisk = ii->ii_index[off % ii->ii_ndisk];
  923                         cbn = ii->ii_startoff + off / ii->ii_ndisk;
  924                 }
  925                 cbn *= cs->sc_ileave;
  926                 ci = &cs->sc_cinfo[ccdisk];
  927         }
  928 
  929         /*
  930          * Fill in the component buf structure.
  931          */
  932         cbp = CCD_GETBUF();
  933         KASSERT(cbp != NULL);
  934         buf_init(&cbp->cb_buf);
  935         cbp->cb_buf.b_flags = bp->b_flags;
  936         cbp->cb_buf.b_oflags = bp->b_oflags;
  937         cbp->cb_buf.b_cflags = bp->b_cflags;
  938         cbp->cb_buf.b_iodone = ccdiodone;
  939         cbp->cb_buf.b_proc = bp->b_proc;
  940         cbp->cb_buf.b_dev = ci->ci_dev;
  941         cbp->cb_buf.b_blkno = cbn + cboff;
  942         cbp->cb_buf.b_data = addr;
  943         cbp->cb_buf.b_vp = ci->ci_vp;
  944         cbp->cb_buf.b_objlock = ci->ci_vp->v_interlock;
  945         if (cs->sc_ileave == 0)
  946                 cbc = dbtob((u_int64_t)(ci->ci_size - cbn));
  947         else
  948                 cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff));
  949         cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount;
  950 
  951         /*
  952          * context for ccdiodone
  953          */
  954         cbp->cb_obp = bp;
  955         cbp->cb_sc = cs;
  956         cbp->cb_comp = ccdisk;
  957 
  958         BIO_COPYPRIO(&cbp->cb_buf, bp);
  959 
  960 #ifdef DEBUG
  961         if (ccddebug & CCDB_IO)
  962                 printf(" dev 0x%"PRIx64"(u%lu): cbp %p bn %" PRId64 " addr %p"
  963                        " bcnt %d\n",
  964                     ci->ci_dev, (unsigned long) (ci-cs->sc_cinfo), cbp,
  965                     cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
  966                     cbp->cb_buf.b_bcount);
  967 #endif
  968 
  969         return (cbp);
  970 }
  971 
  972 /*
  973  * Called at interrupt time.
  974  * Mark the component as done and if all components are done,
  975  * take a ccd interrupt.
  976  */
  977 static void
  978 ccdiodone(struct buf *vbp)
  979 {
  980         struct ccdbuf *cbp = (struct ccdbuf *) vbp;
  981         struct buf *bp = cbp->cb_obp;
  982         struct ccd_softc *cs = cbp->cb_sc;
  983         int count;
  984 
  985 #ifdef DEBUG
  986         if (ccddebug & CCDB_FOLLOW)
  987                 printf("ccdiodone(%p)\n", cbp);
  988         if (ccddebug & CCDB_IO) {
  989                 printf("ccdiodone: bp %p bcount %d resid %d\n",
  990                        bp, bp->b_bcount, bp->b_resid);
  991                 printf(" dev 0x%"PRIx64"(u%d), cbp %p bn %" PRId64 " addr %p"
  992                        " bcnt %d\n",
  993                        cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
  994                        cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
  995                        cbp->cb_buf.b_bcount);
  996         }
  997 #endif
  998 
  999         if (cbp->cb_buf.b_error != 0) {
 1000                 bp->b_error = cbp->cb_buf.b_error;
 1001                 printf("%s: error %d on component %d\n",
 1002                        cs->sc_xname, bp->b_error, cbp->cb_comp);
 1003         }
 1004         count = cbp->cb_buf.b_bcount;
 1005         buf_destroy(&cbp->cb_buf);
 1006         CCD_PUTBUF(cbp);
 1007 
 1008         /*
 1009          * If all done, "interrupt".
 1010          */
 1011         mutex_enter(cs->sc_iolock);
 1012         bp->b_resid -= count;
 1013         if (bp->b_resid < 0)
 1014                 panic("ccdiodone: count");
 1015         if (bp->b_resid == 0) {
 1016                 /*
 1017                  * Request is done for better or worse, wakeup the top half.
 1018                  */
 1019                 if (bp->b_error != 0)
 1020                         bp->b_resid = bp->b_bcount;
 1021                 disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid),
 1022                     (bp->b_flags & B_READ));
 1023                 if (!disk_isbusy(&cs->sc_dkdev)) {
 1024                         if (bufq_peek(cs->sc_bufq) != NULL) {
 1025                                 cv_broadcast(&cs->sc_push);
 1026                         }
 1027                         cv_broadcast(&cs->sc_stop);
 1028                 }
 1029                 mutex_exit(cs->sc_iolock);
 1030                 biodone(bp);
 1031         } else
 1032                 mutex_exit(cs->sc_iolock);
 1033 }
 1034 
 1035 /* ARGSUSED */
 1036 static int
 1037 ccdread(dev_t dev, struct uio *uio, int flags)
 1038 {
 1039         int unit = ccdunit(dev);
 1040         struct ccd_softc *cs;
 1041 
 1042 #ifdef DEBUG
 1043         if (ccddebug & CCDB_FOLLOW)
 1044                 printf("ccdread(0x%"PRIx64", %p)\n", dev, uio);
 1045 #endif
 1046         if ((cs = ccdget(unit, 0)) == NULL)
 1047                 return 0;
 1048 
 1049         /* Unlocked advisory check, ccdstrategy check is synchronous. */
 1050         if ((cs->sc_flags & CCDF_INITED) == 0)
 1051                 return (ENXIO);
 1052 
 1053         return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
 1054 }
 1055 
 1056 /* ARGSUSED */
 1057 static int
 1058 ccdwrite(dev_t dev, struct uio *uio, int flags)
 1059 {
 1060         int unit = ccdunit(dev);
 1061         struct ccd_softc *cs;
 1062 
 1063 #ifdef DEBUG
 1064         if (ccddebug & CCDB_FOLLOW)
 1065                 printf("ccdwrite(0x%"PRIx64", %p)\n", dev, uio);
 1066 #endif
 1067         if ((cs = ccdget(unit, 0)) == NULL)
 1068                 return ENOENT;
 1069 
 1070         /* Unlocked advisory check, ccdstrategy check is synchronous. */
 1071         if ((cs->sc_flags & CCDF_INITED) == 0)
 1072                 return (ENXIO);
 1073 
 1074         return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
 1075 }
 1076 
 1077 int (*compat_ccd_ioctl_60)(dev_t, u_long, void *, int, struct lwp *,
 1078     int (*)(dev_t, u_long, void *, int, struct lwp *)) = (void *)enosys;
 1079 
 1080 static int
 1081 ccdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
 1082 {
 1083         int unit = ccdunit(dev);
 1084         int i, j, lookedup = 0, error = 0;
 1085         int part, pmask, make, hook;
 1086         struct ccd_softc *cs;
 1087         struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
 1088         kauth_cred_t uc;
 1089         char **cpp;
 1090         struct pathbuf *pb;
 1091         struct vnode **vpp;
 1092 #ifdef __HAVE_OLD_DISKLABEL
 1093         struct disklabel newlabel;
 1094 #endif
 1095 
 1096         switch (cmd) {
 1097         case CCDIOCSET:
 1098                 make = 1;
 1099                 break;
 1100         default:
 1101                 MODULE_HOOK_CALL(ccd_ioctl_60_hook,
 1102                                  (0, cmd, NULL, 0, NULL, NULL),
 1103                                  enosys(), hook);
 1104                 if (hook == 0)
 1105                         make = 1;
 1106                 else
 1107                         make = 0;
 1108                 break;
 1109         }
 1110 
 1111         if ((cs = ccdget(unit, make)) == NULL)
 1112                 return ENOENT;
 1113         uc = kauth_cred_get();
 1114 
 1115         MODULE_HOOK_CALL(ccd_ioctl_60_hook,
 1116                          (dev, cmd, data, flag, l, ccdioctl),
 1117                          enosys(), error);
 1118         if (error != ENOSYS)
 1119                 return error;
 1120 
 1121         /* Must be open for writes for these commands... */
 1122         switch (cmd) {
 1123         case CCDIOCSET:
 1124         case CCDIOCCLR:
 1125         case DIOCSDINFO:
 1126         case DIOCWDINFO:
 1127         case DIOCCACHESYNC:
 1128         case DIOCAWEDGE:
 1129         case DIOCDWEDGE:
 1130         case DIOCRMWEDGES:
 1131         case DIOCMWEDGES:
 1132 #ifdef __HAVE_OLD_DISKLABEL
 1133         case ODIOCSDINFO:
 1134         case ODIOCWDINFO:
 1135 #endif
 1136         case DIOCKLABEL:
 1137         case DIOCWLABEL:
 1138                 if ((flag & FWRITE) == 0)
 1139                         return (EBADF);
 1140         }
 1141 
 1142         /* Must be initialized for these... */
 1143         switch (cmd) {
 1144         case CCDIOCCLR:
 1145         case DIOCGDINFO:
 1146         case DIOCGSTRATEGY:
 1147         case DIOCGCACHE:
 1148         case DIOCCACHESYNC:
 1149         case DIOCAWEDGE:
 1150         case DIOCDWEDGE:
 1151         case DIOCLWEDGES:
 1152         case DIOCMWEDGES:
 1153         case DIOCSDINFO:
 1154         case DIOCWDINFO:
 1155         case DIOCGPARTINFO:
 1156         case DIOCWLABEL:
 1157         case DIOCKLABEL:
 1158         case DIOCGDEFLABEL:
 1159 #ifdef __HAVE_OLD_DISKLABEL
 1160         case ODIOCGDINFO:
 1161         case ODIOCSDINFO:
 1162         case ODIOCWDINFO:
 1163         case ODIOCGDEFLABEL:
 1164 #endif
 1165                 if ((cs->sc_flags & CCDF_INITED) == 0)
 1166                         return ENXIO;
 1167         }
 1168 
 1169         error = disk_ioctl(&cs->sc_dkdev, dev, cmd, data, flag, l);
 1170         if (error != EPASSTHROUGH)
 1171                 return error;
 1172 
 1173         switch (cmd) {
 1174         case DIOCGSTRATEGY:
 1175             {
 1176                 struct disk_strategy *dks = (void *)data;
 1177 
 1178                 mutex_enter(cs->sc_iolock);
 1179                 if (cs->sc_bufq != NULL)
 1180                         strlcpy(dks->dks_name,
 1181                             bufq_getstrategyname(cs->sc_bufq),
 1182                             sizeof(dks->dks_name));
 1183                 else
 1184                         error = EINVAL;
 1185                 mutex_exit(cs->sc_iolock);
 1186                 dks->dks_paramlen = 0;
 1187                 break;
 1188             }
 1189 
 1190         case DIOCWDINFO:
 1191         case DIOCSDINFO:
 1192 #ifdef __HAVE_OLD_DISKLABEL
 1193         case ODIOCWDINFO:
 1194         case ODIOCSDINFO:
 1195 #endif
 1196         {
 1197                 struct disklabel *lp;
 1198 #ifdef __HAVE_OLD_DISKLABEL
 1199                 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
 1200                         memset(&newlabel, 0, sizeof newlabel);
 1201                         memcpy(&newlabel, data, sizeof (struct olddisklabel));
 1202                         lp = &newlabel;
 1203                 } else
 1204 #endif
 1205                 lp = (struct disklabel *)data;
 1206 
 1207                 cs->sc_flags |= CCDF_LABELLING;
 1208 
 1209                 error = setdisklabel(cs->sc_dkdev.dk_label,
 1210                     lp, 0, cs->sc_dkdev.dk_cpulabel);
 1211                 if (error == 0) {
 1212                         if (cmd == DIOCWDINFO
 1213 #ifdef __HAVE_OLD_DISKLABEL
 1214                             || cmd == ODIOCWDINFO
 1215 #endif
 1216                            )
 1217                                 error = writedisklabel(CCDLABELDEV(dev),
 1218                                     ccdstrategy, cs->sc_dkdev.dk_label,
 1219                                     cs->sc_dkdev.dk_cpulabel);
 1220                 }
 1221 
 1222                 cs->sc_flags &= ~CCDF_LABELLING;
 1223                 break;
 1224         }
 1225 
 1226         case DIOCKLABEL:
 1227                 if (*(int *)data != 0)
 1228                         cs->sc_flags |= CCDF_KLABEL;
 1229                 else
 1230                         cs->sc_flags &= ~CCDF_KLABEL;
 1231                 break;
 1232 
 1233         case DIOCWLABEL:
 1234                 if (*(int *)data != 0)
 1235                         cs->sc_flags |= CCDF_WLABEL;
 1236                 else
 1237                         cs->sc_flags &= ~CCDF_WLABEL;
 1238                 break;
 1239 
 1240         case DIOCGDEFLABEL:
 1241                 ccdgetdefaultlabel(cs, (struct disklabel *)data);
 1242                 break;
 1243 
 1244 #ifdef __HAVE_OLD_DISKLABEL
 1245         case ODIOCGDEFLABEL:
 1246                 ccdgetdefaultlabel(cs, &newlabel);
 1247                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
 1248                         return ENOTTY;
 1249                 memcpy(data, &newlabel, sizeof (struct olddisklabel));
 1250                 break;
 1251 #endif
 1252         default:
 1253                 error = ENOTTY;
 1254                         break;
 1255         }
 1256 
 1257         if (error != ENOTTY)
 1258                 return error;
 1259 
 1260         mutex_enter(&cs->sc_dvlock);
 1261 
 1262         error = 0;
 1263         switch (cmd) {
 1264         case CCDIOCSET:
 1265                 if (cs->sc_flags & CCDF_INITED) {
 1266                         error = EBUSY;
 1267                         goto out;
 1268                 }
 1269 
 1270                 /* Validate the flags. */
 1271                 if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) {
 1272                         error = EINVAL;
 1273                         goto out;
 1274                 }
 1275 
 1276                 if (ccio->ccio_ndisks > CCD_MAXNDISKS ||
 1277                     ccio->ccio_ndisks == 0) {
 1278                         error = EINVAL;
 1279                         goto out;
 1280                 }
 1281 
 1282                 /* Fill in some important bits. */
 1283                 cs->sc_ileave = ccio->ccio_ileave;
 1284                 cs->sc_nccdisks = ccio->ccio_ndisks;
 1285                 cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK;
 1286 
 1287                 /*
 1288                  * Allocate space for and copy in the array of
 1289                  * component pathnames and device numbers.
 1290                  */
 1291                 cpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*cpp), KM_SLEEP);
 1292                 vpp = kmem_alloc(ccio->ccio_ndisks * sizeof(*vpp), KM_SLEEP);
 1293                 error = copyin(ccio->ccio_disks, cpp,
 1294                     ccio->ccio_ndisks * sizeof(*cpp));
 1295                 if (error) {
 1296                         kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp));
 1297                         kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp));
 1298                         goto out;
 1299                 }
 1300 
 1301 #ifdef DEBUG
 1302                 if (ccddebug & CCDB_INIT)
 1303                         for (i = 0; i < ccio->ccio_ndisks; ++i)
 1304                                 printf("ccdioctl: component %d: %p\n",
 1305                                     i, cpp[i]);
 1306 #endif
 1307 
 1308                 for (i = 0; i < ccio->ccio_ndisks; ++i) {
 1309 #ifdef DEBUG
 1310                         if (ccddebug & CCDB_INIT)
 1311                                 printf("ccdioctl: lookedup = %d\n", lookedup);
 1312 #endif
 1313                         error = pathbuf_copyin(cpp[i], &pb);
 1314                         if (error == 0) {
 1315                                 error = vn_bdev_openpath(pb, &vpp[i], l);
 1316                                 pathbuf_destroy(pb);
 1317                         }
 1318                         if (error != 0) {
 1319                                 for (j = 0; j < lookedup; ++j)
 1320                                         (void)vn_close(vpp[j], FREAD|FWRITE,
 1321                                             uc);
 1322                                 kmem_free(vpp, ccio->ccio_ndisks *
 1323                                     sizeof(*vpp));
 1324                                 kmem_free(cpp, ccio->ccio_ndisks *
 1325                                     sizeof(*cpp));
 1326 
 1327                                 /*
 1328                                  * No component data is allocated,
 1329                                  * nothing is to be freed.
 1330                                 */
 1331                                 cs->sc_nccdisks = 0;
 1332                                 goto out;
 1333                         }
 1334                         ++lookedup;
 1335                 }
 1336 
 1337                 /* Attach the disk. */
 1338                 disk_attach(&cs->sc_dkdev);
 1339                 bufq_alloc(&cs->sc_bufq, "fcfs", 0);
 1340 
 1341                 /*
 1342                  * Initialize the ccd.  Fills in the softc for us.
 1343                  */
 1344                 if ((error = ccdinit(cs, cpp, vpp, l)) != 0) {
 1345                         for (j = 0; j < lookedup; ++j)
 1346                                 (void)vn_close(vpp[j], FREAD|FWRITE,
 1347                                     uc);
 1348                         kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp));
 1349                         kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp));
 1350                         disk_detach(&cs->sc_dkdev);
 1351                         mutex_exit(&cs->sc_dvlock);
 1352                         bufq_free(cs->sc_bufq);
 1353                         return error;
 1354                 }
 1355 
 1356                 /* We can free the temporary variables now. */
 1357                 kmem_free(vpp, ccio->ccio_ndisks * sizeof(*vpp));
 1358                 kmem_free(cpp, ccio->ccio_ndisks * sizeof(*cpp));
 1359 
 1360                 /*
 1361                  * The ccd has been successfully initialized, so
 1362                  * we can place it into the array.  Don't try to
 1363                  * read the disklabel until the disk has been attached,
 1364                  * because space for the disklabel is allocated
 1365                  * in disk_attach();
 1366                  */
 1367                 ccio->ccio_unit = unit;
 1368                 ccio->ccio_size = cs->sc_size;
 1369 
 1370                 /* Try and read the disklabel. */
 1371                 ccdgetdisklabel(dev);
 1372                 disk_set_info(NULL, &cs->sc_dkdev, NULL);
 1373 
 1374                 /* discover wedges */
 1375                 mutex_exit(&cs->sc_dvlock);
 1376                 dkwedge_discover(&cs->sc_dkdev);
 1377                 return 0;
 1378 
 1379         case CCDIOCCLR:
 1380                 /*
 1381                  * Don't unconfigure if any other partitions are open
 1382                  * or if both the character and block flavors of this
 1383                  * partition are open.
 1384                  */
 1385                 part = DISKPART(dev);
 1386                 pmask = (1 << part);
 1387                 if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
 1388                     ((cs->sc_dkdev.dk_bopenmask & pmask) &&
 1389                     (cs->sc_dkdev.dk_copenmask & pmask))) {
 1390                         error = EBUSY;
 1391                         goto out;
 1392                 }
 1393 
 1394                 /* Delete all of our wedges. */
 1395                 dkwedge_delall(&cs->sc_dkdev);
 1396 
 1397                 /* Stop new I/O, wait for in-flight I/O to complete. */
 1398                 mutex_enter(cs->sc_iolock);
 1399                 cs->sc_flags &= ~(CCDF_INITED|CCDF_VLABEL);
 1400                 cs->sc_zap = true;
 1401                 while (disk_isbusy(&cs->sc_dkdev) ||
 1402                     bufq_peek(cs->sc_bufq) != NULL ||
 1403                     cs->sc_thread != NULL) {
 1404                         cv_broadcast(&cs->sc_push);
 1405                         (void)cv_timedwait(&cs->sc_stop, cs->sc_iolock, hz);
 1406                 }
 1407                 mutex_exit(cs->sc_iolock);
 1408 
 1409                 /*
 1410                  * Free ccd_softc information and clear entry.
 1411                  */
 1412 
 1413                 /* Close the components and free their pathnames. */
 1414                 for (i = 0; i < cs->sc_nccdisks; ++i) {
 1415                         /*
 1416                          * XXX: this close could potentially fail and
 1417                          * cause Bad Things.  Maybe we need to force
 1418                          * the close to happen?
 1419                          */
 1420 #ifdef DEBUG
 1421                         if (ccddebug & CCDB_VNODE)
 1422                                 vprint("CCDIOCCLR: vnode info",
 1423                                     cs->sc_cinfo[i].ci_vp);
 1424 #endif
 1425                         (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
 1426                             uc);
 1427                         kmem_free(cs->sc_cinfo[i].ci_path,
 1428                             cs->sc_cinfo[i].ci_pathlen);
 1429                 }
 1430 
 1431                 if (cs->sc_nccdisks != 0) {
 1432                         /* Free interleave index. */
 1433                         for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) {
 1434                                 kmem_free(cs->sc_itable[i].ii_index,
 1435                                     cs->sc_itable[i].ii_indexsz);
 1436                         }
 1437                         /* Free component info and interleave table. */
 1438                         kmem_free(cs->sc_cinfo, cs->sc_nccdisks *
 1439                             sizeof(struct ccdcinfo));
 1440                         kmem_free(cs->sc_itable, (cs->sc_nccdisks + 1) *
 1441                             sizeof(struct ccdiinfo));
 1442                 }
 1443 
 1444                 aprint_normal("%s: detached\n", cs->sc_xname);
 1445 
 1446                 /* Detach the disk. */
 1447                 disk_detach(&cs->sc_dkdev);
 1448                 bufq_free(cs->sc_bufq);
 1449 
 1450                 /* also releases sc_dvlock */
 1451                 ccdput(cs);
 1452 
 1453                 /* Don't break, otherwise cs is read again. */
 1454                 return 0;
 1455 
 1456         case DIOCGCACHE:
 1457             {
 1458                 int dkcache = 0;
 1459 
 1460                 /*
 1461                  * We pass this call down to all components and report
 1462                  * intersection of the flags returned by the components.
 1463                  * If any errors out, we return error. CCD components
 1464                  * can not change unless the device is unconfigured, so
 1465                  * device feature flags will remain static. RCE/WCE can change
 1466                  * of course, if set directly on underlying device.
 1467                  */
 1468                 for (error = 0, i = 0; i < cs->sc_nccdisks; i++) {
 1469                         error = VOP_IOCTL(cs->sc_cinfo[i].ci_vp, cmd, &j,
 1470                                       flag, uc);
 1471                         if (error)
 1472                                 break;
 1473 
 1474                         if (i == 0)
 1475                                 dkcache = j;
 1476                         else
 1477                                 dkcache = DKCACHE_COMBINE(dkcache, j);
 1478                 }
 1479 
 1480                 *((int *)data) = dkcache;
 1481                 break;
 1482             }
 1483 
 1484         case DIOCCACHESYNC:
 1485                 /*
 1486                  * We pass this call down to all components and report
 1487                  * the first error we encounter.
 1488                  */
 1489                 for (error = 0, i = 0; i < cs->sc_nccdisks; i++) {
 1490                         j = VOP_IOCTL(cs->sc_cinfo[i].ci_vp, cmd, data,
 1491                                       flag, uc);
 1492                         if (j != 0 && error == 0)
 1493                                 error = j;
 1494                 }
 1495                 break;
 1496 
 1497 default:
 1498         error = ENOTTY;
 1499                 break;
 1500         }
 1501 
 1502  out:
 1503         mutex_exit(&cs->sc_dvlock);
 1504         return (error);
 1505 }
 1506 
 1507 static int
 1508 ccdsize(dev_t dev)
 1509 {
 1510         struct ccd_softc *cs;
 1511         struct disklabel *lp;
 1512         int part, unit, omask, size;
 1513 
 1514         unit = ccdunit(dev);
 1515         if ((cs = ccdget(unit, 0)) == NULL)
 1516                 return -1;
 1517 
 1518         if ((cs->sc_flags & CCDF_INITED) == 0)
 1519                 return (-1);
 1520 
 1521         part = DISKPART(dev);
 1522         omask = cs->sc_dkdev.dk_openmask & (1 << part);
 1523         lp = cs->sc_dkdev.dk_label;
 1524 
 1525         if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curlwp))
 1526                 return (-1);
 1527 
 1528         if (lp->d_partitions[part].p_fstype != FS_SWAP)
 1529                 size = -1;
 1530         else
 1531                 size = lp->d_partitions[part].p_size *
 1532                     (lp->d_secsize / DEV_BSIZE);
 1533 
 1534         if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curlwp))
 1535                 return (-1);
 1536 
 1537         return (size);
 1538 }
 1539 
 1540 static void
 1541 ccdgetdefaultlabel(struct ccd_softc *cs, struct disklabel *lp)
 1542 {
 1543         struct ccdgeom *ccg = &cs->sc_geom;
 1544 
 1545         memset(lp, 0, sizeof(*lp));
 1546 
 1547         if (cs->sc_size > UINT32_MAX)
 1548                 lp->d_secperunit = UINT32_MAX;
 1549         else
 1550                 lp->d_secperunit = cs->sc_size;
 1551         lp->d_secsize = ccg->ccg_secsize;
 1552         lp->d_nsectors = ccg->ccg_nsectors;
 1553         lp->d_ntracks = ccg->ccg_ntracks;
 1554         lp->d_ncylinders = ccg->ccg_ncylinders;
 1555         lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
 1556 
 1557         strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
 1558         lp->d_type = DKTYPE_CCD;
 1559         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
 1560         lp->d_rpm = 3600;
 1561         lp->d_interleave = 1;
 1562         lp->d_flags = 0;
 1563 
 1564         lp->d_partitions[RAW_PART].p_offset = 0;
 1565         lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
 1566         lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
 1567         lp->d_npartitions = RAW_PART + 1;
 1568 
 1569         lp->d_magic = DISKMAGIC;
 1570         lp->d_magic2 = DISKMAGIC;
 1571         lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
 1572 }
 1573 
 1574 /*
 1575  * Read the disklabel from the ccd.  If one is not present, fake one
 1576  * up.
 1577  */
 1578 static void
 1579 ccdgetdisklabel(dev_t dev)
 1580 {
 1581         int unit = ccdunit(dev);
 1582         struct ccd_softc *cs;
 1583         const char *errstring;
 1584         struct disklabel *lp;
 1585         struct cpu_disklabel *clp;
 1586 
 1587         if ((cs = ccdget(unit, 0)) == NULL)
 1588                 return;
 1589         lp = cs->sc_dkdev.dk_label;
 1590         clp = cs->sc_dkdev.dk_cpulabel;
 1591         KASSERT(mutex_owned(&cs->sc_dvlock));
 1592 
 1593         memset(clp, 0, sizeof(*clp));
 1594 
 1595         ccdgetdefaultlabel(cs, lp);
 1596 
 1597         /*
 1598          * Call the generic disklabel extraction routine.
 1599          */
 1600         cs->sc_flags |= CCDF_RLABEL;
 1601         if ((cs->sc_flags & CCDF_NOLABEL) != 0)
 1602                 errstring = "CCDF_NOLABEL set; ignoring on-disk label";
 1603         else
 1604                 errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
 1605                     cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
 1606         if (errstring)
 1607                 ccdmakedisklabel(cs);
 1608         else {
 1609                 int i;
 1610                 struct partition *pp;
 1611 
 1612                 /*
 1613                  * Sanity check whether the found disklabel is valid.
 1614                  *
 1615                  * This is necessary since total size of ccd may vary
 1616                  * when an interleave is changed even though exactly
 1617                  * same componets are used, and old disklabel may used
 1618                  * if that is found.
 1619                  */
 1620                 if (lp->d_secperunit < UINT32_MAX ?
 1621                         lp->d_secperunit != cs->sc_size :
 1622                         lp->d_secperunit > cs->sc_size)
 1623                         printf("WARNING: %s: "
 1624                             "total sector size in disklabel (%ju) != "
 1625                             "the size of ccd (%ju)\n", cs->sc_xname,
 1626                             (uintmax_t)lp->d_secperunit,
 1627                             (uintmax_t)cs->sc_size);
 1628                 for (i = 0; i < lp->d_npartitions; i++) {
 1629                         pp = &lp->d_partitions[i];
 1630                         if (pp->p_offset + pp->p_size > cs->sc_size)
 1631                                 printf("WARNING: %s: end of partition `%c' "
 1632                                     "exceeds the size of ccd (%ju)\n",
 1633                                     cs->sc_xname, 'a' + i, (uintmax_t)cs->sc_size);
 1634                 }
 1635         }
 1636 
 1637 #ifdef DEBUG
 1638         /* It's actually extremely common to have unlabeled ccds. */
 1639         if (ccddebug & CCDB_LABEL)
 1640                 if (errstring != NULL)
 1641                         printf("%s: %s\n", cs->sc_xname, errstring);
 1642 #endif
 1643 
 1644         /* In-core label now valid. */
 1645         cs->sc_flags = (cs->sc_flags | CCDF_VLABEL) & ~CCDF_RLABEL;
 1646 }
 1647 
 1648 /*
 1649  * Take care of things one might want to take care of in the event
 1650  * that a disklabel isn't present.
 1651  */
 1652 static void
 1653 ccdmakedisklabel(struct ccd_softc *cs)
 1654 {
 1655         struct disklabel *lp = cs->sc_dkdev.dk_label;
 1656 
 1657         /*
 1658          * For historical reasons, if there's no disklabel present
 1659          * the raw partition must be marked FS_BSDFFS.
 1660          */
 1661         lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
 1662 
 1663         strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
 1664 
 1665         lp->d_checksum = dkcksum(lp);
 1666 }
 1667 
 1668 #ifdef DEBUG
 1669 static void
 1670 printiinfo(struct ccdiinfo *ii)
 1671 {
 1672         int ix, i;
 1673 
 1674         for (ix = 0; ii->ii_ndisk; ix++, ii++) {
 1675                 printf(" itab[%d]: #dk %d sblk %" PRId64 " soff %" PRId64,
 1676                     ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
 1677                 for (i = 0; i < ii->ii_ndisk; i++)
 1678                         printf(" %d", ii->ii_index[i]);
 1679                 printf("\n");
 1680         }
 1681 }
 1682 #endif
 1683 
 1684 MODULE(MODULE_CLASS_DRIVER, ccd, "dk_subr,bufq_fcfs");
 1685 
 1686 static int
 1687 ccd_modcmd(modcmd_t cmd, void *arg)
 1688 {
 1689         int error = 0;
 1690 #ifdef _MODULE
 1691         int bmajor = -1, cmajor = -1;
 1692 #endif
 1693 
 1694 
 1695         switch (cmd) {
 1696         case MODULE_CMD_INIT:
 1697 #ifdef _MODULE
 1698                 ccdattach(0);
 1699 
 1700                 error = devsw_attach("ccd", &ccd_bdevsw, &bmajor,
 1701                     &ccd_cdevsw, &cmajor);
 1702 #endif
 1703                 break;
 1704 
 1705         case MODULE_CMD_FINI:
 1706 #ifdef _MODULE
 1707                 mutex_enter(&ccd_lock);
 1708                 if (!LIST_EMPTY(&ccds)) {
 1709                         mutex_exit(&ccd_lock);
 1710                         error = EBUSY;
 1711                 } else {
 1712                         mutex_exit(&ccd_lock);
 1713                         devsw_detach(&ccd_bdevsw, &ccd_cdevsw);
 1714                         ccddetach();
 1715                 }
 1716 #endif
 1717                 break;
 1718 
 1719         case MODULE_CMD_STAT:
 1720                 return ENOTTY;
 1721 
 1722         default:
 1723                 return ENOTTY;
 1724         }
 1725 
 1726         return error;
 1727 }
 1728 
 1729 static int
 1730 ccd_units_sysctl(SYSCTLFN_ARGS)
 1731 {
 1732         struct sysctlnode node;
 1733         struct ccd_softc *sc;
 1734         int error, i, nccd, *units;
 1735         size_t size;
 1736 
 1737         nccd = 0;
 1738         mutex_enter(&ccd_lock);
 1739         LIST_FOREACH(sc, &ccds, sc_link)
 1740                 nccd++;
 1741         mutex_exit(&ccd_lock);
 1742 
 1743         if (nccd != 0) {
 1744                 size = nccd * sizeof(*units);
 1745                 units = kmem_zalloc(size, KM_SLEEP);
 1746                 i = 0;
 1747                 mutex_enter(&ccd_lock);
 1748                 LIST_FOREACH(sc, &ccds, sc_link) {
 1749                         if (i >= nccd)
 1750                                 break;
 1751                         units[i] = sc->sc_unit;
 1752                 }
 1753                 mutex_exit(&ccd_lock);
 1754         } else {
 1755                 units = NULL;
 1756                 size = 0;
 1757         }
 1758 
 1759         node = *rnode;
 1760         node.sysctl_data = units;
 1761         node.sysctl_size = size;
 1762 
 1763         error = sysctl_lookup(SYSCTLFN_CALL(&node));
 1764         if (units)
 1765                 kmem_free(units, size);
 1766         return error;
 1767 }
 1768 
 1769 static int
 1770 ccd_info_sysctl(SYSCTLFN_ARGS)
 1771 {
 1772         struct sysctlnode node;
 1773         struct ccddiskinfo ccd;
 1774         struct ccd_softc *sc;
 1775         int unit;
 1776 
 1777         if (newp == NULL || newlen != sizeof(int))
 1778                 return EINVAL;
 1779 
 1780         unit = *(const int *)newp;
 1781         newp = NULL;
 1782         newlen = 0;
 1783         ccd.ccd_ndisks = ~0;
 1784         mutex_enter(&ccd_lock);
 1785         LIST_FOREACH(sc, &ccds, sc_link) {
 1786                 if (sc->sc_unit == unit) {
 1787                         ccd.ccd_ileave = sc->sc_ileave;
 1788                         ccd.ccd_size = sc->sc_size;
 1789                         ccd.ccd_ndisks = sc->sc_nccdisks;
 1790                         ccd.ccd_flags = sc->sc_flags;
 1791                         break;
 1792                 }
 1793         }
 1794         mutex_exit(&ccd_lock);
 1795 
 1796         if (ccd.ccd_ndisks == ~0)
 1797                 return ENOENT;
 1798 
 1799         node = *rnode;
 1800         node.sysctl_data = &ccd;
 1801         node.sysctl_size = sizeof(ccd);
 1802 
 1803         return sysctl_lookup(SYSCTLFN_CALL(&node));
 1804 }
 1805 
 1806 static int
 1807 ccd_components_sysctl(SYSCTLFN_ARGS)
 1808 {
 1809         struct sysctlnode node;
 1810         int error, unit;
 1811         size_t size;
 1812         char *names, *p, *ep;
 1813         struct ccd_softc *sc;
 1814 
 1815         if (newp == NULL || newlen != sizeof(int))
 1816                 return EINVAL;
 1817 
 1818         size = 0;
 1819         unit = *(const int *)newp;
 1820         newp = NULL;
 1821         newlen = 0;
 1822         mutex_enter(&ccd_lock);
 1823         LIST_FOREACH(sc, &ccds, sc_link)
 1824                 if (sc->sc_unit == unit) {
 1825                         for (size_t i = 0; i < sc->sc_nccdisks; i++)
 1826                                 size += strlen(sc->sc_cinfo[i].ci_path) + 1;
 1827                         break;
 1828                 }
 1829         mutex_exit(&ccd_lock);
 1830 
 1831         if (size == 0)
 1832                 return ENOENT;
 1833         names = kmem_zalloc(size, KM_SLEEP);
 1834         p = names;
 1835         ep = names + size;
 1836         mutex_enter(&ccd_lock);
 1837         LIST_FOREACH(sc, &ccds, sc_link)
 1838                 if (sc->sc_unit == unit) {
 1839                         for (size_t i = 0; i < sc->sc_nccdisks; i++) {
 1840                                 char *d = sc->sc_cinfo[i].ci_path;
 1841                                 while (p < ep && (*p++ = *d++) != '\0')
 1842                                         continue;
 1843                         }
 1844                         break;
 1845                 }
 1846         mutex_exit(&ccd_lock);
 1847 
 1848         node = *rnode;
 1849         node.sysctl_data = names;
 1850         node.sysctl_size = ep - names;
 1851 
 1852         error = sysctl_lookup(SYSCTLFN_CALL(&node));
 1853         kmem_free(names, size);
 1854         return error;
 1855 }
 1856 
 1857 SYSCTL_SETUP(sysctl_kern_ccd_setup, "sysctl kern.ccd subtree setup")
 1858 {
 1859         const struct sysctlnode *node = NULL;
 1860 
 1861         sysctl_createv(clog, 0, NULL, &node,
 1862             CTLFLAG_PERMANENT,
 1863             CTLTYPE_NODE, "ccd",
 1864             SYSCTL_DESCR("ConCatenated Disk state"),
 1865             NULL, 0, NULL, 0,
 1866             CTL_KERN, CTL_CREATE, CTL_EOL);
 1867 
 1868         if (node == NULL)
 1869                 return;
 1870 
 1871         sysctl_createv(clog, 0, &node, NULL,
 1872             CTLFLAG_PERMANENT | CTLFLAG_READONLY,
 1873             CTLTYPE_STRUCT, "units",
 1874             SYSCTL_DESCR("List of ccd unit numbers"),
 1875             ccd_units_sysctl, 0, NULL, 0,
 1876             CTL_CREATE, CTL_EOL);
 1877         sysctl_createv(clog, 0, &node, NULL,
 1878             CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
 1879             CTLTYPE_STRUCT, "info",
 1880             SYSCTL_DESCR("Information about a CCD unit"),
 1881             ccd_info_sysctl, 0, NULL, 0,
 1882             CTL_CREATE, CTL_EOL);
 1883         sysctl_createv(clog, 0, &node, NULL,
 1884             CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
 1885             CTLTYPE_STRUCT, "components",
 1886             SYSCTL_DESCR("Information about CCD components"),
 1887             ccd_components_sysctl, 0, NULL, 0,
 1888             CTL_CREATE, CTL_EOL);
 1889 }

Cache object: ae9a4e1b7cab927ae5259dcc13e707f0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.