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

Cache object: c49578e1259316cf90d3fcf4cbdd6a21


[ 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.