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/geom/geom_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 /*-
    2  * SPDX-License-Identifier: (BSD-2-Clause-NetBSD AND BSD-3-Clause)
    3  *
    4  * Copyright (c) 2003 Poul-Henning Kamp.
    5  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Jason R. Thorpe.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  *
   32  * $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ 
   33  */
   34 
   35 /*-
   36  * Copyright (c) 1988 University of Utah.
   37  * Copyright (c) 1990, 1993
   38  *      The Regents of the University of California.  All rights reserved.
   39  *
   40  * This code is derived from software contributed to Berkeley by
   41  * the Systems Programming Group of the University of Utah Computer
   42  * Science Department.
   43  *
   44  * Redistribution and use in source and binary forms, with or without
   45  * modification, are permitted provided that the following conditions
   46  * are met:
   47  * 1. Redistributions of source code must retain the above copyright
   48  *    notice, this list of conditions and the following disclaimer.
   49  * 2. Redistributions in binary form must reproduce the above copyright
   50  *    notice, this list of conditions and the following disclaimer in the
   51  *    documentation and/or other materials provided with the distribution.
   52  * 3. Neither the name of the University nor the names of its contributors
   53  *    may be used to endorse or promote products derived from this software
   54  *    without specific prior written permission.
   55  *
   56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   66  * SUCH DAMAGE.
   67  *
   68  * from: Utah $Hdr: cd.c 1.6 90/11/28$
   69  *
   70  *      @(#)cd.c        8.2 (Berkeley) 11/16/93
   71  */
   72 
   73 /*
   74  * Dynamic configuration and disklabel support by:
   75  *      Jason R. Thorpe <thorpej@nas.nasa.gov>
   76  *      Numerical Aerodynamic Simulation Facility
   77  *      Mail Stop 258-6
   78  *      NASA Ames Research Center
   79  *      Moffett Field, CA 94035
   80  */
   81 
   82 #include <sys/cdefs.h>
   83 __FBSDID("$FreeBSD$");
   84 
   85 #include <sys/param.h>
   86 #include <sys/systm.h>
   87 #include <sys/kernel.h>
   88 #include <sys/module.h>
   89 #include <sys/bio.h>
   90 #include <sys/malloc.h>
   91 #include <sys/sbuf.h>
   92 #include <geom/geom.h>
   93 
   94 /*
   95  * Number of blocks to untouched in front of a component partition.
   96  * This is to avoid violating its disklabel area when it starts at the
   97  * beginning of the slice.
   98  */
   99 #if !defined(CCD_OFFSET)
  100 #define CCD_OFFSET 16
  101 #endif
  102 
  103 /* sc_flags */
  104 #define CCDF_UNIFORM    0x02    /* use LCCD of sizes for uniform interleave */
  105 #define CCDF_MIRROR     0x04    /* use mirroring */
  106 #define CCDF_NO_OFFSET  0x08    /* do not leave space in front */
  107 #define CCDF_LINUX      0x10    /* use Linux compatibility mode */
  108 
  109 /* Mask of user-settable ccd flags. */
  110 #define CCDF_USERMASK   (CCDF_UNIFORM|CCDF_MIRROR)
  111 
  112 /*
  113  * Interleave description table.
  114  * Computed at boot time to speed irregular-interleave lookups.
  115  * The idea is that we interleave in "groups".  First we interleave
  116  * evenly over all component disks up to the size of the smallest
  117  * component (the first group), then we interleave evenly over all
  118  * remaining disks up to the size of the next-smallest (second group),
  119  * and so on.
  120  *
  121  * Each table entry describes the interleave characteristics of one
  122  * of these groups.  For example if a concatenated disk consisted of
  123  * three components of 5, 3, and 7 DEV_BSIZE blocks interleaved at
  124  * DEV_BSIZE (1), the table would have three entries:
  125  *
  126  *      ndisk   startblk        startoff        dev
  127  *      3       0               0               0, 1, 2
  128  *      2       9               3               0, 2
  129  *      1       13              5               2
  130  *      0       -               -               -
  131  *
  132  * which says that the first nine blocks (0-8) are interleaved over
  133  * 3 disks (0, 1, 2) starting at block offset 0 on any component disk,
  134  * the next 4 blocks (9-12) are interleaved over 2 disks (0, 2) starting
  135  * at component block 3, and the remaining blocks (13-14) are on disk
  136  * 2 starting at offset 5.
  137  */
  138 struct ccdiinfo {
  139         int     ii_ndisk;       /* # of disks range is interleaved over */
  140         daddr_t ii_startblk;    /* starting scaled block # for range */
  141         daddr_t ii_startoff;    /* starting component offset (block #) */
  142         int     *ii_index;      /* ordered list of components in range */
  143 };
  144 
  145 /*
  146  * Component info table.
  147  * Describes a single component of a concatenated disk.
  148  */
  149 struct ccdcinfo {
  150         daddr_t         ci_size;                /* size */
  151         struct g_provider *ci_provider;         /* provider */
  152         struct g_consumer *ci_consumer;         /* consumer */
  153 };
  154 
  155 /*
  156  * A concatenated disk is described by this structure.
  157  */
  158 
  159 struct ccd_s {
  160         LIST_ENTRY(ccd_s) list;
  161 
  162         int              sc_unit;               /* logical unit number */
  163         int              sc_flags;              /* flags */
  164         daddr_t          sc_size;               /* size of ccd */
  165         int              sc_ileave;             /* interleave */
  166         u_int            sc_ndisks;             /* number of components */
  167         struct ccdcinfo  *sc_cinfo;             /* component info */
  168         struct ccdiinfo  *sc_itable;            /* interleave table */
  169         uint32_t         sc_secsize;            /* # bytes per sector */
  170         int              sc_pick;               /* side of mirror picked */
  171         daddr_t          sc_blk[2];             /* mirror localization */
  172         uint32_t         sc_offset;             /* actual offset used */
  173 };
  174 
  175 static g_start_t g_ccd_start;
  176 static void ccdiodone(struct bio *bp);
  177 static void ccdinterleave(struct ccd_s *);
  178 static int ccdinit(struct gctl_req *req, struct ccd_s *);
  179 static int ccdbuffer(struct bio **ret, struct ccd_s *,
  180                       struct bio *, daddr_t, caddr_t, long);
  181 
  182 static void
  183 g_ccd_orphan(struct g_consumer *cp)
  184 {
  185         /*
  186          * XXX: We don't do anything here.  It is not obvious
  187          * XXX: what DTRT would be, so we do what the previous
  188          * XXX: code did: ignore it and let the user cope.
  189          */
  190 }
  191 
  192 static int
  193 g_ccd_access(struct g_provider *pp, int dr, int dw, int de)
  194 {
  195         struct g_geom *gp;
  196         struct g_consumer *cp1, *cp2;
  197         int error;
  198 
  199         de += dr;
  200         de += dw;
  201 
  202         gp = pp->geom;
  203         error = ENXIO;
  204         LIST_FOREACH(cp1, &gp->consumer, consumer) {
  205                 error = g_access(cp1, dr, dw, de);
  206                 if (error) {
  207                         LIST_FOREACH(cp2, &gp->consumer, consumer) {
  208                                 if (cp1 == cp2)
  209                                         break;
  210                                 g_access(cp2, -dr, -dw, -de);
  211                         }
  212                         break;
  213                 }
  214         }
  215         return (error);
  216 }
  217 
  218 /*
  219  * Free the softc and its substructures.
  220  */
  221 static void
  222 g_ccd_freesc(struct ccd_s *sc)
  223 {
  224         struct ccdiinfo *ii;
  225 
  226         g_free(sc->sc_cinfo);
  227         if (sc->sc_itable != NULL) {
  228                 for (ii = sc->sc_itable; ii->ii_ndisk > 0; ii++)
  229                         g_free(ii->ii_index);
  230                 g_free(sc->sc_itable);
  231         }
  232         g_free(sc);
  233 }
  234 
  235 static int
  236 ccdinit(struct gctl_req *req, struct ccd_s *cs)
  237 {
  238         struct ccdcinfo *ci;
  239         daddr_t size;
  240         int ix;
  241         daddr_t minsize;
  242         int maxsecsize;
  243         off_t mediasize;
  244         u_int sectorsize;
  245 
  246         cs->sc_size = 0;
  247 
  248         maxsecsize = 0;
  249         minsize = 0;
  250 
  251         if (cs->sc_flags & CCDF_LINUX) {
  252                 cs->sc_offset = 0;
  253                 cs->sc_ileave *= 2;
  254                 if (cs->sc_flags & CCDF_MIRROR && cs->sc_ndisks != 2)
  255                         gctl_error(req, "Mirror mode for Linux raids is "
  256                                         "only supported with 2 devices");
  257         } else {
  258                 if (cs->sc_flags & CCDF_NO_OFFSET)
  259                         cs->sc_offset = 0;
  260                 else
  261                         cs->sc_offset = CCD_OFFSET;
  262         }
  263         for (ix = 0; ix < cs->sc_ndisks; ix++) {
  264                 ci = &cs->sc_cinfo[ix];
  265 
  266                 mediasize = ci->ci_provider->mediasize;
  267                 sectorsize = ci->ci_provider->sectorsize;
  268                 if (sectorsize > maxsecsize)
  269                         maxsecsize = sectorsize;
  270                 size = mediasize / DEV_BSIZE - cs->sc_offset;
  271 
  272                 /* Truncate to interleave boundary */
  273 
  274                 if (cs->sc_ileave > 1)
  275                         size -= size % cs->sc_ileave;
  276 
  277                 if (size == 0) {
  278                         gctl_error(req, "Component %s has effective size zero",
  279                             ci->ci_provider->name);
  280                         return(ENODEV);
  281                 }
  282 
  283                 if (minsize == 0 || size < minsize)
  284                         minsize = size;
  285                 ci->ci_size = size;
  286                 cs->sc_size += size;
  287         }
  288 
  289         /*
  290          * Don't allow the interleave to be smaller than
  291          * the biggest component sector.
  292          */
  293         if ((cs->sc_ileave > 0) &&
  294             (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
  295                 gctl_error(req, "Interleave to small for sector size");
  296                 return(EINVAL);
  297         }
  298 
  299         /*
  300          * If uniform interleave is desired set all sizes to that of
  301          * the smallest component.  This will guarantee that a single
  302          * interleave table is generated.
  303          *
  304          * Lost space must be taken into account when calculating the
  305          * overall size.  Half the space is lost when CCDF_MIRROR is
  306          * specified.
  307          */
  308         if (cs->sc_flags & CCDF_UNIFORM) {
  309                 for (ix = 0; ix < cs->sc_ndisks; ix++) {
  310                         ci = &cs->sc_cinfo[ix];
  311                         ci->ci_size = minsize;
  312                 }
  313                 cs->sc_size = cs->sc_ndisks * minsize;
  314         }
  315 
  316         if (cs->sc_flags & CCDF_MIRROR) {
  317                 /*
  318                  * Check to see if an even number of components
  319                  * have been specified.  The interleave must also
  320                  * be non-zero in order for us to be able to 
  321                  * guarantee the topology.
  322                  */
  323                 if (cs->sc_ndisks % 2) {
  324                         gctl_error(req,
  325                               "Mirroring requires an even number of disks");
  326                         return(EINVAL);
  327                 }
  328                 if (cs->sc_ileave == 0) {
  329                         gctl_error(req,
  330                              "An interleave must be specified when mirroring");
  331                         return(EINVAL);
  332                 }
  333                 cs->sc_size = (cs->sc_ndisks/2) * minsize;
  334         } 
  335 
  336         /*
  337          * Construct the interleave table.
  338          */
  339         ccdinterleave(cs);
  340 
  341         /*
  342          * Create pseudo-geometry based on 1MB cylinders.  It's
  343          * pretty close.
  344          */
  345         cs->sc_secsize = maxsecsize;
  346 
  347         return (0);
  348 }
  349 
  350 static void
  351 ccdinterleave(struct ccd_s *cs)
  352 {
  353         struct ccdcinfo *ci, *smallci;
  354         struct ccdiinfo *ii;
  355         daddr_t bn, lbn;
  356         int ix;
  357         daddr_t size;
  358 
  359         /*
  360          * Allocate an interleave table.  The worst case occurs when each
  361          * of N disks is of a different size, resulting in N interleave
  362          * tables.
  363          *
  364          * Chances are this is too big, but we don't care.
  365          */
  366         size = (cs->sc_ndisks + 1) * sizeof(struct ccdiinfo);
  367         cs->sc_itable = g_malloc(size, M_WAITOK | M_ZERO);
  368 
  369         /*
  370          * Trivial case: no interleave (actually interleave of disk size).
  371          * Each table entry represents a single component in its entirety.
  372          *
  373          * An interleave of 0 may not be used with a mirror setup.
  374          */
  375         if (cs->sc_ileave == 0) {
  376                 bn = 0;
  377                 ii = cs->sc_itable;
  378 
  379                 for (ix = 0; ix < cs->sc_ndisks; ix++) {
  380                         /* Allocate space for ii_index. */
  381                         ii->ii_index = g_malloc(sizeof(int), M_WAITOK);
  382                         ii->ii_ndisk = 1;
  383                         ii->ii_startblk = bn;
  384                         ii->ii_startoff = 0;
  385                         ii->ii_index[0] = ix;
  386                         bn += cs->sc_cinfo[ix].ci_size;
  387                         ii++;
  388                 }
  389                 ii->ii_ndisk = 0;
  390                 return;
  391         }
  392 
  393         /*
  394          * The following isn't fast or pretty; it doesn't have to be.
  395          */
  396         size = 0;
  397         bn = lbn = 0;
  398         for (ii = cs->sc_itable; ; ii++) {
  399                 /*
  400                  * Allocate space for ii_index.  We might allocate more then
  401                  * we use.
  402                  */
  403                 ii->ii_index = g_malloc((sizeof(int) * cs->sc_ndisks),
  404                     M_WAITOK);
  405 
  406                 /*
  407                  * Locate the smallest of the remaining components
  408                  */
  409                 smallci = NULL;
  410                 for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_ndisks]; 
  411                     ci++) {
  412                         if (ci->ci_size > size &&
  413                             (smallci == NULL ||
  414                              ci->ci_size < smallci->ci_size)) {
  415                                 smallci = ci;
  416                         }
  417                 }
  418 
  419                 /*
  420                  * Nobody left, all done
  421                  */
  422                 if (smallci == NULL) {
  423                         ii->ii_ndisk = 0;
  424                         g_free(ii->ii_index);
  425                         ii->ii_index = NULL;
  426                         break;
  427                 }
  428 
  429                 /*
  430                  * Record starting logical block using an sc_ileave blocksize.
  431                  */
  432                 ii->ii_startblk = bn / cs->sc_ileave;
  433 
  434                 /*
  435                  * Record starting component block using an sc_ileave 
  436                  * blocksize.  This value is relative to the beginning of
  437                  * a component disk.
  438                  */
  439                 ii->ii_startoff = lbn;
  440 
  441                 /*
  442                  * Determine how many disks take part in this interleave
  443                  * and record their indices.
  444                  */
  445                 ix = 0;
  446                 for (ci = cs->sc_cinfo; 
  447                     ci < &cs->sc_cinfo[cs->sc_ndisks]; ci++) {
  448                         if (ci->ci_size >= smallci->ci_size) {
  449                                 ii->ii_index[ix++] = ci - cs->sc_cinfo;
  450                         }
  451                 }
  452                 ii->ii_ndisk = ix;
  453                 bn += ix * (smallci->ci_size - size);
  454                 lbn = smallci->ci_size / cs->sc_ileave;
  455                 size = smallci->ci_size;
  456         }
  457 }
  458 
  459 static void
  460 g_ccd_start(struct bio *bp)
  461 {
  462         long bcount, rcount;
  463         struct bio *cbp[2];
  464         caddr_t addr;
  465         daddr_t bn;
  466         int err;
  467         struct ccd_s *cs;
  468 
  469         cs = bp->bio_to->geom->softc;
  470 
  471         /*
  472          * Block all GETATTR requests, we wouldn't know which of our
  473          * subdevices we should ship it off to.
  474          * XXX: this may not be the right policy.
  475          */
  476         if(bp->bio_cmd == BIO_GETATTR) {
  477                 g_io_deliver(bp, EINVAL);
  478                 return;
  479         }
  480 
  481         /*
  482          * Translate the partition-relative block number to an absolute.
  483          */
  484         bn = bp->bio_offset / cs->sc_secsize;
  485 
  486         /*
  487          * Allocate component buffers and fire off the requests
  488          */
  489         addr = bp->bio_data;
  490         for (bcount = bp->bio_length; bcount > 0; bcount -= rcount) {
  491                 err = ccdbuffer(cbp, cs, bp, bn, addr, bcount);
  492                 if (err) {
  493                         bp->bio_completed += bcount;
  494                         if (bp->bio_error == 0)
  495                                 bp->bio_error = err;
  496                         if (bp->bio_completed == bp->bio_length)
  497                                 g_io_deliver(bp, bp->bio_error);
  498                         return;
  499                 }
  500                 rcount = cbp[0]->bio_length;
  501 
  502                 if (cs->sc_flags & CCDF_MIRROR) {
  503                         /*
  504                          * Mirroring.  Writes go to both disks, reads are
  505                          * taken from whichever disk seems most appropriate.
  506                          *
  507                          * We attempt to localize reads to the disk whos arm
  508                          * is nearest the read request.  We ignore seeks due
  509                          * to writes when making this determination and we
  510                          * also try to avoid hogging.
  511                          */
  512                         if (cbp[0]->bio_cmd != BIO_READ) {
  513                                 g_io_request(cbp[0], cbp[0]->bio_from);
  514                                 g_io_request(cbp[1], cbp[1]->bio_from);
  515                         } else {
  516                                 int pick = cs->sc_pick;
  517                                 daddr_t range = cs->sc_size / 16;
  518 
  519                                 if (bn < cs->sc_blk[pick] - range ||
  520                                     bn > cs->sc_blk[pick] + range
  521                                 ) {
  522                                         cs->sc_pick = pick = 1 - pick;
  523                                 }
  524                                 cs->sc_blk[pick] = bn + btodb(rcount);
  525                                 g_io_request(cbp[pick], cbp[pick]->bio_from);
  526                         }
  527                 } else {
  528                         /*
  529                          * Not mirroring
  530                          */
  531                         g_io_request(cbp[0], cbp[0]->bio_from);
  532                 }
  533                 bn += btodb(rcount);
  534                 addr += rcount;
  535         }
  536 }
  537 
  538 /*
  539  * Build a component buffer header.
  540  */
  541 static int
  542 ccdbuffer(struct bio **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, caddr_t addr, long bcount)
  543 {
  544         struct ccdcinfo *ci, *ci2 = NULL;
  545         struct bio *cbp;
  546         daddr_t cbn, cboff;
  547         off_t cbc;
  548 
  549         /*
  550          * Determine which component bn falls in.
  551          */
  552         cbn = bn;
  553         cboff = 0;
  554 
  555         if (cs->sc_ileave == 0) {
  556                 /*
  557                  * Serially concatenated and neither a mirror nor a parity
  558                  * config.  This is a special case.
  559                  */
  560                 daddr_t sblk;
  561 
  562                 sblk = 0;
  563                 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
  564                         sblk += ci->ci_size;
  565                 cbn -= sblk;
  566         } else {
  567                 struct ccdiinfo *ii;
  568                 int ccdisk, off;
  569 
  570                 /*
  571                  * Calculate cbn, the logical superblock (sc_ileave chunks),
  572                  * and cboff, a normal block offset (DEV_BSIZE chunks) relative
  573                  * to cbn.
  574                  */
  575                 cboff = cbn % cs->sc_ileave;    /* DEV_BSIZE gran */
  576                 cbn = cbn / cs->sc_ileave;      /* DEV_BSIZE * ileave gran */
  577 
  578                 /*
  579                  * Figure out which interleave table to use.
  580                  */
  581                 for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
  582                         if (ii->ii_startblk > cbn)
  583                                 break;
  584                 }
  585                 ii--;
  586 
  587                 /*
  588                  * off is the logical superblock relative to the beginning 
  589                  * of this interleave block.  
  590                  */
  591                 off = cbn - ii->ii_startblk;
  592 
  593                 /*
  594                  * We must calculate which disk component to use (ccdisk),
  595                  * and recalculate cbn to be the superblock relative to
  596                  * the beginning of the component.  This is typically done by
  597                  * adding 'off' and ii->ii_startoff together.  However, 'off'
  598                  * must typically be divided by the number of components in
  599                  * this interleave array to be properly convert it from a
  600                  * CCD-relative logical superblock number to a 
  601                  * component-relative superblock number.
  602                  */
  603                 if (ii->ii_ndisk == 1) {
  604                         /*
  605                          * When we have just one disk, it can't be a mirror
  606                          * or a parity config.
  607                          */
  608                         ccdisk = ii->ii_index[0];
  609                         cbn = ii->ii_startoff + off;
  610                 } else {
  611                         if (cs->sc_flags & CCDF_MIRROR) {
  612                                 /*
  613                                  * We have forced a uniform mapping, resulting
  614                                  * in a single interleave array.  We double
  615                                  * up on the first half of the available
  616                                  * components and our mirror is in the second
  617                                  * half.  This only works with a single 
  618                                  * interleave array because doubling up
  619                                  * doubles the number of sectors, so there
  620                                  * cannot be another interleave array because
  621                                  * the next interleave array's calculations
  622                                  * would be off.
  623                                  */
  624                                 int ndisk2 = ii->ii_ndisk / 2;
  625                                 ccdisk = ii->ii_index[off % ndisk2];
  626                                 cbn = ii->ii_startoff + off / ndisk2;
  627                                 ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
  628                         } else {
  629                                 ccdisk = ii->ii_index[off % ii->ii_ndisk];
  630                                 cbn = ii->ii_startoff + off / ii->ii_ndisk;
  631                         }
  632                 }
  633 
  634                 ci = &cs->sc_cinfo[ccdisk];
  635 
  636                 /*
  637                  * Convert cbn from a superblock to a normal block so it
  638                  * can be used to calculate (along with cboff) the normal
  639                  * block index into this particular disk.
  640                  */
  641                 cbn *= cs->sc_ileave;
  642         }
  643 
  644         /*
  645          * Fill in the component buf structure.
  646          */
  647         cbp = g_clone_bio(bp);
  648         if (cbp == NULL)
  649                 return (ENOMEM);
  650         cbp->bio_done = g_std_done;
  651         cbp->bio_offset = dbtob(cbn + cboff + cs->sc_offset);
  652         cbp->bio_data = addr;
  653         if (cs->sc_ileave == 0)
  654               cbc = dbtob((off_t)(ci->ci_size - cbn));
  655         else
  656               cbc = dbtob((off_t)(cs->sc_ileave - cboff));
  657         cbp->bio_length = (cbc < bcount) ? cbc : bcount;
  658 
  659         cbp->bio_from = ci->ci_consumer;
  660         cb[0] = cbp;
  661 
  662         if (cs->sc_flags & CCDF_MIRROR) {
  663                 cbp = g_clone_bio(bp);
  664                 if (cbp == NULL)
  665                         return (ENOMEM);
  666                 cbp->bio_done = cb[0]->bio_done = ccdiodone;
  667                 cbp->bio_offset = cb[0]->bio_offset;
  668                 cbp->bio_data = cb[0]->bio_data;
  669                 cbp->bio_length = cb[0]->bio_length;
  670                 cbp->bio_from = ci2->ci_consumer;
  671                 cbp->bio_caller1 = cb[0];
  672                 cb[0]->bio_caller1 = cbp;
  673                 cb[1] = cbp;
  674         }
  675         return (0);
  676 }
  677 
  678 /*
  679  * Called only for mirrored operations.
  680  */
  681 static void
  682 ccdiodone(struct bio *cbp)
  683 {
  684         struct bio *mbp, *pbp;
  685 
  686         mbp = cbp->bio_caller1;
  687         pbp = cbp->bio_parent;
  688 
  689         if (pbp->bio_cmd == BIO_READ) {
  690                 if (cbp->bio_error == 0) {
  691                         /* We will not be needing the partner bio */
  692                         if (mbp != NULL) {
  693                                 pbp->bio_inbed++;
  694                                 g_destroy_bio(mbp);
  695                         }
  696                         g_std_done(cbp);
  697                         return;
  698                 }
  699                 if (mbp != NULL) {
  700                         /* Try partner the bio instead */
  701                         mbp->bio_caller1 = NULL;
  702                         pbp->bio_inbed++;
  703                         g_destroy_bio(cbp);
  704                         g_io_request(mbp, mbp->bio_from);
  705                         /*
  706                          * XXX: If this comes back OK, we should actually
  707                          * try to write the good data on the failed mirror
  708                          */
  709                         return;
  710                 }
  711                 g_std_done(cbp);
  712                 return;
  713         }
  714         if (mbp != NULL) {
  715                 mbp->bio_caller1 = NULL;
  716                 pbp->bio_inbed++;
  717                 if (cbp->bio_error != 0 && pbp->bio_error == 0)
  718                         pbp->bio_error = cbp->bio_error;
  719                 g_destroy_bio(cbp);
  720                 return;
  721         }
  722         g_std_done(cbp);
  723 }
  724 
  725 static void
  726 g_ccd_create(struct gctl_req *req, struct g_class *mp)
  727 {
  728         int *unit, *ileave, *nprovider;
  729         struct g_geom *gp;
  730         struct g_consumer *cp;
  731         struct g_provider *pp;
  732         struct ccd_s *sc;
  733         struct sbuf *sb;
  734         char buf[20];
  735         int i, error;
  736 
  737         g_topology_assert();
  738         unit = gctl_get_paraml(req, "unit", sizeof (*unit));
  739         if (unit == NULL) {
  740                 gctl_error(req, "unit parameter not given");
  741                 return;
  742         }
  743         ileave = gctl_get_paraml(req, "ileave", sizeof (*ileave));
  744         if (ileave == NULL) {
  745                 gctl_error(req, "ileave parameter not given");
  746                 return;
  747         }
  748         nprovider = gctl_get_paraml(req, "nprovider", sizeof (*nprovider));
  749         if (nprovider == NULL) {
  750                 gctl_error(req, "nprovider parameter not given");
  751                 return;
  752         }
  753 
  754         /* Check for duplicate unit */
  755         LIST_FOREACH(gp, &mp->geom, geom) {
  756                 sc = gp->softc;
  757                 if (sc != NULL && sc->sc_unit == *unit) {
  758                         gctl_error(req, "Unit %d already configured", *unit);
  759                         return;
  760                 }
  761         }
  762 
  763         if (*nprovider <= 0) {
  764                 gctl_error(req, "Bogus nprovider argument (= %d)", *nprovider);
  765                 return;
  766         }
  767 
  768         /* Check all providers are valid */
  769         for (i = 0; i < *nprovider; i++) {
  770                 snprintf(buf, sizeof(buf), "provider%d", i);
  771                 pp = gctl_get_provider(req, buf);
  772                 if (pp == NULL)
  773                         return;
  774         }
  775 
  776         gp = g_new_geomf(mp, "ccd%d", *unit);
  777         sc = g_malloc(sizeof *sc, M_WAITOK | M_ZERO);
  778         gp->softc = sc;
  779         sc->sc_ndisks = *nprovider;
  780 
  781         /* Allocate space for the component info. */
  782         sc->sc_cinfo = g_malloc(sc->sc_ndisks * sizeof(struct ccdcinfo),
  783             M_WAITOK | M_ZERO);
  784 
  785         /* Create consumers and attach to all providers */
  786         for (i = 0; i < *nprovider; i++) {
  787                 snprintf(buf, sizeof(buf), "provider%d", i);
  788                 pp = gctl_get_provider(req, buf);
  789                 cp = g_new_consumer(gp);
  790                 error = g_attach(cp, pp);
  791                 KASSERT(error == 0, ("attach to %s failed", pp->name));
  792                 sc->sc_cinfo[i].ci_consumer = cp;
  793                 sc->sc_cinfo[i].ci_provider = pp;
  794         }
  795 
  796         sc->sc_unit = *unit;
  797         sc->sc_ileave = *ileave;
  798 
  799         if (gctl_get_param(req, "no_offset", NULL))
  800                 sc->sc_flags |= CCDF_NO_OFFSET;
  801         if (gctl_get_param(req, "linux", NULL))
  802                 sc->sc_flags |= CCDF_LINUX;
  803 
  804         if (gctl_get_param(req, "uniform", NULL))
  805                 sc->sc_flags |= CCDF_UNIFORM;
  806         if (gctl_get_param(req, "mirror", NULL))
  807                 sc->sc_flags |= CCDF_MIRROR;
  808 
  809         if (sc->sc_ileave == 0 && (sc->sc_flags & CCDF_MIRROR)) {
  810                 printf("%s: disabling mirror, interleave is 0\n", gp->name);
  811                 sc->sc_flags &= ~(CCDF_MIRROR);
  812         }
  813 
  814         if ((sc->sc_flags & CCDF_MIRROR) && !(sc->sc_flags & CCDF_UNIFORM)) {
  815                 printf("%s: mirror/parity forces uniform flag\n", gp->name);
  816                 sc->sc_flags |= CCDF_UNIFORM;
  817         }
  818 
  819         error = ccdinit(req, sc);
  820         if (error != 0) {
  821                 g_ccd_freesc(sc);
  822                 gp->softc = NULL;
  823                 g_wither_geom(gp, ENXIO);
  824                 return;
  825         }
  826 
  827         pp = g_new_providerf(gp, "%s", gp->name);
  828         pp->mediasize = sc->sc_size * (off_t)sc->sc_secsize;
  829         pp->sectorsize = sc->sc_secsize;
  830         g_error_provider(pp, 0);
  831 
  832         sb = sbuf_new_auto();
  833         sbuf_printf(sb, "ccd%d: %d components ", sc->sc_unit, *nprovider);
  834         for (i = 0; i < *nprovider; i++) {
  835                 sbuf_printf(sb, "%s%s",
  836                     i == 0 ? "(" : ", ", 
  837                     sc->sc_cinfo[i].ci_provider->name);
  838         }
  839         sbuf_printf(sb, "), %jd blocks ", (off_t)pp->mediasize / DEV_BSIZE);
  840         if (sc->sc_ileave != 0)
  841                 sbuf_printf(sb, "interleaved at %d blocks\n",
  842                         sc->sc_ileave);
  843         else
  844                 sbuf_printf(sb, "concatenated\n");
  845         sbuf_finish(sb);
  846         gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
  847         sbuf_delete(sb);
  848 }
  849 
  850 static int
  851 g_ccd_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
  852 {
  853         struct g_provider *pp;
  854         struct ccd_s *sc;
  855 
  856         g_topology_assert();
  857         sc = gp->softc;
  858         pp = LIST_FIRST(&gp->provider);
  859         if (sc == NULL || pp == NULL)
  860                 return (EBUSY);
  861         if (pp->acr != 0 || pp->acw != 0 || pp->ace != 0) {
  862                 gctl_error(req, "%s is open(r%dw%de%d)", gp->name,
  863                     pp->acr, pp->acw, pp->ace);
  864                 return (EBUSY);
  865         }
  866         g_ccd_freesc(sc);
  867         gp->softc = NULL;
  868         g_wither_geom(gp, ENXIO);
  869         return (0);
  870 }
  871 
  872 static void
  873 g_ccd_list(struct gctl_req *req, struct g_class *mp)
  874 {
  875         struct sbuf *sb;
  876         struct ccd_s *cs;
  877         struct g_geom *gp;
  878         int i, unit, *up;
  879 
  880         up = gctl_get_paraml(req, "unit", sizeof (*up));
  881         if (up == NULL) {
  882                 gctl_error(req, "unit parameter not given");
  883                 return;
  884         }
  885         unit = *up;
  886         sb = sbuf_new_auto();
  887         LIST_FOREACH(gp, &mp->geom, geom) {
  888                 cs = gp->softc;
  889                 if (cs == NULL || (unit >= 0 && unit != cs->sc_unit))
  890                         continue;
  891                 sbuf_printf(sb, "ccd%d\t\t%d\t%d\t",
  892                     cs->sc_unit, cs->sc_ileave, cs->sc_flags & CCDF_USERMASK);
  893                         
  894                 for (i = 0; i < cs->sc_ndisks; ++i) {
  895                         sbuf_printf(sb, "%s/dev/%s", i == 0 ? "" : " ",
  896                             cs->sc_cinfo[i].ci_provider->name);
  897                 }
  898                 sbuf_printf(sb, "\n");
  899         }
  900         sbuf_finish(sb);
  901         gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
  902         sbuf_delete(sb);
  903 }
  904 
  905 static void
  906 g_ccd_config(struct gctl_req *req, struct g_class *mp, char const *verb)
  907 {
  908         struct g_geom *gp;
  909 
  910         g_topology_assert();
  911         if (!strcmp(verb, "create geom")) {
  912                 g_ccd_create(req, mp);
  913         } else if (!strcmp(verb, "destroy geom")) {
  914                 gp = gctl_get_geom(req, mp, "geom");
  915                 if (gp != NULL)
  916                         g_ccd_destroy_geom(req, mp, gp);
  917         } else if (!strcmp(verb, "list")) {
  918                 g_ccd_list(req, mp);
  919         } else {
  920                 gctl_error(req, "unknown verb");
  921         }
  922 }
  923 
  924 static struct g_class g_ccd_class = {
  925         .name = "CCD",
  926         .version = G_VERSION,
  927         .ctlreq = g_ccd_config,
  928         .destroy_geom = g_ccd_destroy_geom,
  929         .start = g_ccd_start,
  930         .orphan = g_ccd_orphan,
  931         .access = g_ccd_access,
  932 };
  933 
  934 DECLARE_GEOM_CLASS(g_ccd_class, g_ccd);
  935 MODULE_VERSION(geom_ccd, 0);

Cache object: 5d6499bcb1076c893672a3c408a4a1b7


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