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_bsd.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  * Copyright (c) 2002 Poul-Henning Kamp
    3  * Copyright (c) 2002 Networks Associates Technology, Inc.
    4  * All rights reserved.
    5  *
    6  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
    7  * and NAI Labs, the Security Research Division of Network Associates, Inc.
    8  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
    9  * DARPA CHATS research program.
   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  * 3. The names of the authors may not be used to endorse or promote
   20  *    products derived from this software without specific prior written
   21  *    permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  * $FreeBSD: releng/5.1/sys/geom/geom_bsd.c 114785 2003-05-06 19:36:13Z phk $
   36  *
   37  * This is the method for dealing with BSD disklabels.  It has been
   38  * extensively (by my standards at least) commented, in the vain hope that
   39  * it will serve as the source in future copy&paste operations.
   40  */
   41 
   42 #include <sys/param.h>
   43 #include <sys/endian.h>
   44 #include <sys/systm.h>
   45 #include <sys/kernel.h>
   46 #include <sys/conf.h>
   47 #include <sys/bio.h>
   48 #include <sys/malloc.h>
   49 #include <sys/lock.h>
   50 #include <sys/mutex.h>
   51 #include <sys/md5.h>
   52 #include <sys/errno.h>
   53 #include <sys/disklabel.h>
   54 #include <geom/geom.h>
   55 #include <geom/geom_slice.h>
   56 
   57 #define BSD_CLASS_NAME "BSD"
   58 
   59 #define ALPHA_LABEL_OFFSET      64
   60 
   61 #define LABELSIZE (148 + 16 * MAXPARTITIONS)
   62 
   63 static void g_bsd_hotwrite(void *arg, int flag);
   64 /*
   65  * Our private data about one instance.  All the rest is handled by the
   66  * slice code and stored in its softc, so this is just the stuff
   67  * specific to BSD disklabels.
   68  */
   69 struct g_bsd_softc {
   70         off_t   labeloffset;
   71         off_t   mbroffset;
   72         off_t   rawoffset;
   73         struct disklabel ondisk;
   74         u_char  label[LABELSIZE];
   75         u_char  labelsum[16];
   76 };
   77 
   78 /*
   79  * Modify our slicer to match proposed disklabel, if possible.
   80  * This is where we make sure we don't do something stupid.
   81  */
   82 static int
   83 g_bsd_modify(struct g_geom *gp, u_char *label)
   84 {
   85         int i, error;
   86         struct partition *ppp;
   87         struct g_slicer *gsp;
   88         struct g_consumer *cp;
   89         struct g_bsd_softc *ms;
   90         u_int secsize, u;
   91         off_t mediasize, rawoffset, o;
   92         struct disklabel dl;
   93         MD5_CTX md5sum;
   94 
   95         g_topology_assert();
   96         gsp = gp->softc;
   97         ms = gsp->softc;
   98 
   99         error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS);
  100         if (error) {
  101                 return (error);
  102         }
  103 
  104         /* Get dimensions of our device. */
  105         cp = LIST_FIRST(&gp->consumer);
  106         secsize = cp->provider->sectorsize;
  107         mediasize = cp->provider->mediasize;
  108 
  109 #ifdef notyet
  110         /*
  111          * Indications are that the d_secperunit is not correctly
  112          * initialized in many cases, and since we don't need it
  113          * for anything, we dont strictly need this test.
  114          * Preemptive action to avoid confusing people in disklabel(8)
  115          * may be in order.
  116          */
  117         /* The label cannot claim a larger size than the media. */
  118         if ((off_t)dl.d_secperunit * dl.d_secsize > mediasize)
  119                 return (EINVAL);
  120 #endif
  121 
  122         /* ... or a smaller sector size. */
  123         if (dl.d_secsize < secsize) {
  124                 return (EINVAL);
  125         }
  126 
  127         /* ... or a non-multiple sector size. */
  128         if (dl.d_secsize % secsize != 0) {
  129                 return (EINVAL);
  130         }
  131 
  132         /* Historical braindamage... */
  133         rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize;
  134 
  135         for (i = 0; i < dl.d_npartitions; i++) {
  136                 ppp = &dl.d_partitions[i];
  137                 if (ppp->p_size == 0)
  138                         continue;
  139                 o = (off_t)ppp->p_offset * dl.d_secsize;
  140 
  141                 if (o < rawoffset)
  142                         rawoffset = 0;
  143         }
  144         
  145         if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset)
  146                 printf("WARNING: Expected rawoffset %jd, found %jd\n",
  147                     (intmax_t)ms->mbroffset/dl.d_secsize,
  148                     (intmax_t)rawoffset/dl.d_secsize);
  149 
  150         /* Don't munge open partitions. */
  151         for (i = 0; i < dl.d_npartitions; i++) {
  152                 ppp = &dl.d_partitions[i];
  153 
  154                 o = (off_t)ppp->p_offset * dl.d_secsize;
  155                 if (o == 0)
  156                         o = rawoffset;
  157                 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
  158                     o - rawoffset,
  159                     (off_t)ppp->p_size * dl.d_secsize,
  160                      dl.d_secsize,
  161                     "%s%c", gp->name, 'a' + i);
  162                 if (error)
  163                         return (error);
  164         }
  165 
  166         /* Look good, go for it... */
  167         for (u = 0; u < gsp->nslice; u++) {
  168                 ppp = &dl.d_partitions[u];
  169                 o = (off_t)ppp->p_offset * dl.d_secsize;
  170                 if (o == 0)
  171                         o = rawoffset;
  172                 g_slice_config(gp, u, G_SLICE_CONFIG_SET,
  173                     o - rawoffset,
  174                     (off_t)ppp->p_size * dl.d_secsize,
  175                      dl.d_secsize,
  176                     "%s%c", gp->name, 'a' + u);
  177         }
  178 
  179         /* Update our softc */
  180         ms->ondisk = dl;
  181         if (label != ms->label)
  182                 bcopy(label, ms->label, LABELSIZE);
  183         ms->rawoffset = rawoffset;
  184 
  185         /*
  186          * In order to avoid recursively attaching to the same
  187          * on-disk label (it's usually visible through the 'c'
  188          * partition) we calculate an MD5 and ask if other BSD's
  189          * below us love that label.  If they do, we don't.
  190          */
  191         MD5Init(&md5sum);
  192         MD5Update(&md5sum, ms->label, sizeof(ms->label));
  193         MD5Final(ms->labelsum, &md5sum);
  194 
  195         return (0);
  196 }
  197 
  198 /*
  199  * This is an internal helper function, called multiple times from the taste
  200  * function to try to locate a disklabel on the disk.  More civilized formats
  201  * will not need this, as there is only one possible place on disk to look
  202  * for the magic spot.
  203  */
  204 
  205 static int
  206 g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset)
  207 {
  208         int error;
  209         u_char *buf;
  210         struct disklabel *dl;
  211         off_t secoff;
  212 
  213         /*
  214          * We need to read entire aligned sectors, and we assume that the
  215          * disklabel does not span sectors, so one sector is enough.
  216          */
  217         error = 0;
  218         secoff = offset % secsize;
  219         buf = g_read_data(cp, offset - secoff, secsize, &error);
  220         if (buf == NULL || error != 0)
  221                 return (ENOENT);
  222 
  223         /* Decode into our native format. */
  224         dl = &ms->ondisk;
  225         error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS);
  226         if (!error)
  227                 bcopy(buf + secoff, ms->label, LABELSIZE);
  228 
  229         /* Remember to free the buffer g_read_data() gave us. */
  230         g_free(buf);
  231 
  232         ms->labeloffset = offset;
  233         return (error);
  234 }
  235 
  236 /*
  237  * This function writes the current label to disk, possibly updating
  238  * the alpha SRM checksum.
  239  */
  240 
  241 static int
  242 g_bsd_writelabel(struct g_geom *gp, u_char *bootcode)
  243 {
  244         off_t secoff;
  245         u_int secsize;
  246         struct g_consumer *cp;
  247         struct g_slicer *gsp;
  248         struct g_bsd_softc *ms;
  249         u_char *buf;
  250         uint64_t sum;
  251         int error, i;
  252 
  253         gsp = gp->softc;
  254         ms = gsp->softc;
  255         cp = LIST_FIRST(&gp->consumer);
  256         /* Get sector size, we need it to read data. */
  257         secsize = cp->provider->sectorsize;
  258         secoff = ms->labeloffset % secsize;
  259         if (bootcode == NULL) {
  260                 buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error);
  261                 if (buf == NULL || error != 0)
  262                         return (error);
  263                 bcopy(ms->label, buf + secoff, sizeof(ms->label));
  264         } else {
  265                 buf = bootcode;
  266                 bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label));
  267         }
  268         if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
  269                 sum = 0;
  270                 for (i = 0; i < 63; i++)
  271                         sum += le64dec(buf + i * 8);
  272                 le64enc(buf + 504, sum);
  273         }
  274         if (bootcode == NULL) {
  275                 error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize);
  276                 g_free(buf);
  277         } else {
  278                 error = g_write_data(cp, 0, bootcode, BBSIZE);
  279         }
  280         return(error);
  281 }
  282 
  283 
  284 /*
  285  * Implement certain ioctls to modify disklabels with.  This function
  286  * is called by the event handler thread with topology locked as result
  287  * of the g_post_event() in g_bsd_start().  It is not necessary to keep
  288  * topology locked all the time but make sure to return with topology
  289  * locked as well.
  290  */
  291 
  292 static void
  293 g_bsd_ioctl(void *arg, int flag)
  294 {
  295         struct bio *bp;
  296         struct g_geom *gp;
  297         struct g_slicer *gsp;
  298         struct g_bsd_softc *ms;
  299         struct g_ioctl *gio;
  300         u_char *label;
  301         int error;
  302 
  303         g_topology_assert();
  304         bp = arg;
  305         if (flag == EV_CANCEL) {
  306                 g_io_deliver(bp, ENXIO);
  307                 return;
  308         }
  309 
  310         gp = bp->bio_to->geom;
  311         gsp = gp->softc;
  312         ms = gsp->softc;
  313         gio = (struct g_ioctl *)bp->bio_data;
  314 
  315         label = g_malloc(LABELSIZE, M_WAITOK);
  316 
  317         /* The disklabel to set is the ioctl argument. */
  318         bsd_disklabel_le_enc(label, gio->data);
  319 
  320         /* Validate and modify our slice instance to match. */
  321         error = g_bsd_modify(gp, label);        /* Picks up topology lock on success. */
  322         g_free(label);
  323         if (error || gio->cmd == DIOCSDINFO) {
  324                 g_io_deliver(bp, error);
  325                 return;
  326         }
  327         
  328         KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl"));
  329         g_io_deliver(bp, g_bsd_writelabel(gp, NULL));
  330 }
  331 
  332 /*
  333  * Rewrite the bootblock, which is BBSIZE bytes from the start of the disk.
  334  * We punch down the disklabel where we expect it to be before writing.
  335  */
  336 static int
  337 g_bsd_diocbsdbb(dev_t dev, u_long cmd __unused, caddr_t data, int fflag __unused, struct thread *td __unused)
  338 {
  339         struct g_geom *gp;
  340         struct g_slicer *gsp;
  341         struct g_bsd_softc *ms;
  342         struct g_consumer *cp;
  343         u_char *buf;
  344         void *p;
  345         u_int secsize;
  346         int error, i;
  347         uint64_t sum;
  348 
  349         /* Get hold of the interesting bits from the bio. */
  350         gp = (void *)dev;
  351         gsp = gp->softc;
  352         ms = gsp->softc;
  353 
  354         /* The disklabel to set is the ioctl argument. */
  355         buf = g_malloc(BBSIZE, M_WAITOK);
  356         p = *(void **)data;
  357         error = copyin(p, buf, BBSIZE);
  358         if (!error) {
  359                 DROP_GIANT();
  360                 g_topology_lock();
  361                 /* Validate and modify our slice instance to match. */
  362                 error = g_bsd_modify(gp, buf + ms->labeloffset);
  363                 if (!error) {
  364                         cp = LIST_FIRST(&gp->consumer);
  365                         secsize = cp->provider->sectorsize;
  366                         if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
  367                                 sum = 0;
  368                                 for (i = 0; i < 63; i++)
  369                                         sum += le64dec(buf + i * 8);
  370                                 le64enc(buf + 504, sum);
  371                         }
  372                         error = g_write_data(cp, 0, buf, BBSIZE);
  373                 }
  374                 g_topology_unlock();
  375                 PICKUP_GIANT();
  376         }
  377         g_free(buf);
  378         return (error);
  379 }
  380 
  381 /*
  382  * If the user tries to overwrite our disklabel through an open partition
  383  * or via a magicwrite config call, we end up here and try to prevent
  384  * footshooting as best we can.
  385  */
  386 static void
  387 g_bsd_hotwrite(void *arg, int flag)
  388 {
  389         struct bio *bp;
  390         struct g_geom *gp;
  391         struct g_slicer *gsp;
  392         struct g_slice *gsl;
  393         struct g_bsd_softc *ms;
  394         u_char *p;
  395         int error;
  396         
  397         g_topology_assert();
  398         /*
  399          * We should never get canceled, because that would amount to a removal
  400          * of the geom while there was outstanding I/O requests.
  401          */
  402         KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled"));
  403         bp = arg;
  404         gp = bp->bio_to->geom;
  405         gsp = gp->softc;
  406         ms = gsp->softc;
  407         gsl = &gsp->slices[bp->bio_to->index];
  408         p = (u_char*)bp->bio_data + ms->labeloffset 
  409             - (bp->bio_offset + gsl->offset);
  410         error = g_bsd_modify(gp, p);
  411         if (error) {
  412                 g_io_deliver(bp, EPERM);
  413                 return;
  414         }
  415         g_slice_finish_hot(bp);
  416 }
  417 
  418 /*-
  419  * This start routine is only called for non-trivial requests, all the
  420  * trivial ones are handled autonomously by the slice code.
  421  * For requests we handle here, we must call the g_io_deliver() on the
  422  * bio, and return non-zero to indicate to the slice code that we did so.
  423  * This code executes in the "DOWN" I/O path, this means:
  424  *    * No sleeping.
  425  *    * Don't grab the topology lock.
  426  *    * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
  427  */
  428 
  429 static int
  430 g_bsd_start(struct bio *bp)
  431 {
  432         struct g_geom *gp;
  433         struct g_bsd_softc *ms;
  434         struct g_slicer *gsp;
  435         struct g_ioctl *gio;
  436         int error;
  437 
  438         gp = bp->bio_to->geom;
  439         gsp = gp->softc;
  440         ms = gsp->softc;
  441         switch(bp->bio_cmd) {
  442         case BIO_GETATTR:
  443                 if (g_handleattr(bp, "BSD::labelsum", ms->labelsum,
  444                     sizeof(ms->labelsum)))
  445                         return (1);
  446                 break;
  447         default:
  448                 KASSERT(0 == 1, ("Unknown bio_cmd in g_bsd_start (%d)",
  449                     bp->bio_cmd));
  450         }
  451 
  452         /* We only handle ioctl(2) requests of the right format. */
  453         if (strcmp(bp->bio_attribute, "GEOM::ioctl"))
  454                 return (0);
  455         else if (bp->bio_length != sizeof(*gio))
  456                 return (0);
  457 
  458         /* Get hold of the ioctl parameters. */
  459         gio = (struct g_ioctl *)bp->bio_data;
  460 
  461         switch (gio->cmd) {
  462         case DIOCGDINFO:
  463                 /* Return a copy of the disklabel to userland. */
  464                 bsd_disklabel_le_dec(ms->label, gio->data, MAXPARTITIONS);
  465                 g_io_deliver(bp, 0);
  466                 return (1);
  467         case DIOCBSDBB:
  468                 gio->func = g_bsd_diocbsdbb;
  469                 gio->dev = (void *)gp;
  470                 g_io_deliver(bp, EDIRIOCTL);
  471                 return (1);
  472         case DIOCSDINFO:
  473         case DIOCWDINFO:
  474                 /*
  475                  * These we cannot do without the topology lock and some
  476                  * some I/O requests.  Ask the event-handler to schedule
  477                  * us in a less restricted environment.
  478                  */
  479                 error = g_post_event(g_bsd_ioctl, bp, M_NOWAIT, gp, NULL);
  480                 if (error)
  481                         g_io_deliver(bp, error);
  482                 /*
  483                  * We must return non-zero to indicate that we will deal
  484                  * with this bio, even though we have not done so yet.
  485                  */
  486                 return (1);
  487         default:
  488                 return (0);
  489         }
  490 }
  491 
  492 /*
  493  * Dump configuration information in XML format.
  494  * Notice that the function is called once for the geom and once for each
  495  * consumer and provider.  We let g_slice_dumpconf() do most of the work.
  496  */
  497 static void
  498 g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
  499 {
  500         struct g_bsd_softc *ms;
  501         struct g_slicer *gsp;
  502 
  503         gsp = gp->softc;
  504         ms = gsp->softc;
  505         g_slice_dumpconf(sb, indent, gp, cp, pp);
  506         if (indent != NULL && pp == NULL && cp == NULL) {
  507                 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n",
  508                     indent, (intmax_t)ms->labeloffset);
  509                 sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n",
  510                     indent, (intmax_t)ms->rawoffset);
  511                 sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n",
  512                     indent, (intmax_t)ms->mbroffset);
  513         } else if (pp != NULL) {
  514                 if (indent == NULL)
  515                         sbuf_printf(sb, " ty %d",
  516                             ms->ondisk.d_partitions[pp->index].p_fstype);
  517                 else
  518                         sbuf_printf(sb, "%s<type>%d</type>\n", indent,
  519                             ms->ondisk.d_partitions[pp->index].p_fstype);
  520         }
  521 }
  522 
  523 /*
  524  * The taste function is called from the event-handler, with the topology
  525  * lock already held and a provider to examine.  The flags are unused.
  526  *
  527  * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and
  528  * if we find valid, consistent magic on it, build a geom on it.
  529  * any magic bits which indicate that we should automatically put a BSD
  530  * geom on it.
  531  *
  532  * There may be cases where the operator would like to put a BSD-geom on
  533  * providers which do not meet all of the requirements.  This can be done
  534  * by instead passing the G_TF_INSIST flag, which will override these
  535  * checks.
  536  *
  537  * The final flags value is G_TF_TRANSPARENT, which instructs the method
  538  * to put a geom on top of the provider and configure it to be as transparent
  539  * as possible.  This is not really relevant to the BSD method and therefore
  540  * not implemented here.
  541  */
  542 
  543 static struct g_geom *
  544 g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags)
  545 {
  546         struct g_geom *gp;
  547         struct g_consumer *cp;
  548         int error, i;
  549         struct g_bsd_softc *ms;
  550         u_int secsize;
  551         struct g_slicer *gsp;
  552         u_char hash[16];
  553         MD5_CTX md5sum;
  554 
  555         g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name);
  556         g_topology_assert();
  557 
  558         /* We don't implement transparent inserts. */
  559         if (flags == G_TF_TRANSPARENT)
  560                 return (NULL);
  561 
  562         /*
  563          * BSD labels are a subclass of the general "slicing" topology so
  564          * a lot of the work can be done by the common "slice" code.
  565          * Create a geom with space for MAXPARTITIONS providers, one consumer
  566          * and a softc structure for us.  Specify the provider to attach
  567          * the consumer to and our "start" routine for special requests.
  568          * The provider is opened with mode (1,0,0) so we can do reads
  569          * from it.
  570          */
  571         gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms,
  572              sizeof(*ms), g_bsd_start);
  573         if (gp == NULL)
  574                 return (NULL);
  575 
  576         /*
  577          * Fill in the optional details, in our case we have a dumpconf
  578          * routine which the "slice" code should call at the right time
  579          */
  580         gp->dumpconf = g_bsd_dumpconf;
  581 
  582         /* Get the geom_slicer softc from the geom. */
  583         gsp = gp->softc;
  584 
  585         /*
  586          * The do...while loop here allows us to have multiple escapes
  587          * using a simple "break".  This improves code clarity without
  588          * ending up in deep nesting and without using goto or come from.
  589          */
  590         do {
  591                 /*
  592                  * If the provider is an MBR we will only auto attach
  593                  * to type 165 slices in the G_TF_NORMAL case.  We will
  594                  * attach to any other type.
  595                  */
  596                 error = g_getattr("MBR::type", cp, &i);
  597                 if (!error) {
  598                         if (i != 165 && flags == G_TF_NORMAL)
  599                                 break;
  600                         error = g_getattr("MBR::offset", cp, &ms->mbroffset);
  601                         if (error)
  602                                 break;
  603                 }
  604 
  605                 /* Same thing if we are inside a PC98 */
  606                 error = g_getattr("PC98::type", cp, &i);
  607                 if (!error) {
  608                         if (i != 0xc494 && flags == G_TF_NORMAL)
  609                                 break;
  610                         error = g_getattr("PC98::offset", cp, &ms->mbroffset);
  611                         if (error)
  612                                 break;
  613                 }
  614 
  615                 /* Get sector size, we need it to read data. */
  616                 secsize = cp->provider->sectorsize;
  617                 if (secsize < 512)
  618                         break;
  619 
  620                 /* First look for a label at the start of the second sector. */
  621                 error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize);
  622 
  623                 /* Next, look for alpha labels */
  624                 if (error)
  625                         error = g_bsd_try(gp, gsp, cp, secsize, ms,
  626                             ALPHA_LABEL_OFFSET);
  627 
  628                 /* If we didn't find a label, punt. */
  629                 if (error)
  630                         break;
  631 
  632                 /*
  633                  * In order to avoid recursively attaching to the same
  634                  * on-disk label (it's usually visible through the 'c'
  635                  * partition) we calculate an MD5 and ask if other BSD's
  636                  * below us love that label.  If they do, we don't.
  637                  */
  638                 MD5Init(&md5sum);
  639                 MD5Update(&md5sum, ms->label, sizeof(ms->label));
  640                 MD5Final(ms->labelsum, &md5sum);
  641 
  642                 error = g_getattr("BSD::labelsum", cp, &hash);
  643                 if (!error && !strncmp(ms->labelsum, hash, sizeof(hash)))
  644                         break;
  645 
  646                 /*
  647                  * Process the found disklabel, and modify our "slice"
  648                  * instance to match it, if possible.
  649                  */
  650                 error = g_bsd_modify(gp, ms->label);
  651         } while (0);
  652 
  653         /* Success or failure, we can close our provider now. */
  654         error = g_access_rel(cp, -1, 0, 0);
  655 
  656         /* If we have configured any providers, return the new geom. */
  657         if (gsp->nprovider > 0) {
  658                 g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE,
  659                     G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL);
  660                 gsp->hot = g_bsd_hotwrite;
  661                 return (gp);
  662         }
  663         /*
  664          * ...else push the "self-destruct" button, by spoiling our own
  665          * consumer.  This triggers a call to g_slice_spoiled which will
  666          * dismantle what was setup.
  667          */
  668         g_slice_spoiled(cp);
  669         return (NULL);
  670 }
  671 
  672 struct h0h0 {
  673         struct g_geom *gp;
  674         struct g_bsd_softc *ms;
  675         u_char *label;
  676         int error;
  677 };
  678 
  679 static void
  680 g_bsd_callconfig(void *arg, int flag)
  681 {
  682         struct h0h0 *hp;
  683 
  684         hp = arg;
  685         hp->error = g_bsd_modify(hp->gp, hp->label);
  686         if (!hp->error)
  687                 hp->error = g_bsd_writelabel(hp->gp, NULL);
  688 }
  689 
  690 /*
  691  * NB! curthread is user process which GCTL'ed.
  692  */
  693 static int
  694 g_bsd_config(struct gctl_req *req, struct g_geom *gp, const char *verb)
  695 {
  696         u_char *label;
  697         int error, i;
  698         struct h0h0 h0h0;
  699         struct g_slicer *gsp;
  700         struct g_consumer *cp;
  701         struct g_bsd_softc *ms;
  702 
  703         i = 0;
  704         g_topology_assert();
  705         cp = LIST_FIRST(&gp->consumer);
  706         gsp = gp->softc;
  707         ms = gsp->softc;
  708         if (!strcmp(verb, "read mbroffset")) {
  709                 error = gctl_set_param(req, "mbroffset",
  710                     &ms->mbroffset, sizeof(ms->mbroffset));
  711                 return (error);
  712         } else if (!strcmp(verb, "write label")) {
  713                 label = gctl_get_paraml(req, "label", LABELSIZE);
  714                 if (label == NULL)
  715                         return (EINVAL);
  716                 h0h0.gp = gp;
  717                 h0h0.ms = gsp->softc;
  718                 h0h0.label = label;
  719                 h0h0.error = -1;
  720                 /* XXX: Does this reference register with our selfdestruct code ? */
  721                 error = g_access_rel(cp, 1, 1, 1);
  722                 if (error) {
  723                         g_free(label);
  724                         return (error);
  725                 }
  726                 g_topology_unlock();
  727                 g_waitfor_event(g_bsd_callconfig, &h0h0, M_WAITOK, gp, NULL);
  728                 g_topology_lock();
  729                 error = h0h0.error;
  730                 g_access_rel(cp, -1, -1, -1);
  731                 g_free(label);
  732         } else if (!strcmp(verb, "write bootcode")) {
  733                 label = gctl_get_paraml(req, "bootcode", BBSIZE);
  734                 if (label == NULL)
  735                         return (EINVAL);
  736                 /* XXX: Does this reference register with our selfdestruct code ? */
  737                 error = g_access_rel(cp, 1, 1, 1);
  738                 if (error) {
  739                         g_free(label);
  740                         return (error);
  741                 }
  742                 error = g_bsd_writelabel(gp, label);
  743                 g_access_rel(cp, -1, -1, -1);
  744                 g_free(label);
  745         } else {
  746                 return (gctl_error(req, "Unknown verb parameter"));
  747         }
  748 
  749         return (error);
  750 }
  751 
  752 /* Finally, register with GEOM infrastructure. */
  753 static struct g_class g_bsd_class = {
  754         .name = BSD_CLASS_NAME,
  755         .taste = g_bsd_taste,
  756         .config_geom = g_bsd_config,
  757         G_CLASS_INITIALIZER
  758 };
  759 
  760 DECLARE_GEOM_CLASS(g_bsd_class, g_bsd);

Cache object: ba3de052c634993acf0f518a4a2a130a


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