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.0/sys/geom/geom_bsd.c 109195 2003-01-13 21:09:20Z jhb $
   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 server as the source in future copy&paste operations.
   40  */
   41 
   42 #include <sys/param.h>
   43 #ifndef _KERNEL
   44 #include <stdio.h>
   45 #include <string.h>
   46 #include <stdlib.h>
   47 #include <signal.h>
   48 #include <err.h>
   49 #else
   50 #include <sys/systm.h>
   51 #include <sys/kernel.h>
   52 #include <sys/conf.h>
   53 #include <sys/bio.h>
   54 #include <sys/malloc.h>
   55 #include <sys/lock.h>
   56 #include <sys/mutex.h>
   57 #endif
   58 #include <sys/stdint.h>
   59 #include <sys/errno.h>
   60 #include <sys/disklabel.h>
   61 #include <geom/geom.h>
   62 #include <geom/geom_slice.h>
   63 
   64 #define BSD_CLASS_NAME "BSD"
   65 
   66 #define ALPHA_LABEL_OFFSET      64
   67 
   68 /*
   69  * Our private data about one instance.  All the rest is handled by the
   70  * slice code and stored in its softc, so this is just the stuff
   71  * specific to BSD disklabels.
   72  */
   73 struct g_bsd_softc {
   74         off_t   labeloffset;
   75         off_t   mbroffset;
   76         off_t   rawoffset;
   77         struct disklabel ondisk;
   78         struct disklabel inram;
   79 };
   80 
   81 /*
   82  * The next 4 functions isolate us from how the compiler lays out and pads
   83  * "struct disklabel".  We treat what we read from disk as a bytestream and
   84  * explicitly convert it into a struct disklabel.  This makes us compiler-
   85  * endianness- and wordsize- agnostic.
   86  * For now we only have little-endian formats to deal with.
   87  */
   88 
   89 static void
   90 g_bsd_ledec_partition(u_char *ptr, struct partition *d)
   91 {
   92         d->p_size = g_dec_le4(ptr + 0);
   93         d->p_offset = g_dec_le4(ptr + 4);
   94         d->p_fsize = g_dec_le4(ptr + 8);
   95         d->p_fstype = ptr[12];
   96         d->p_frag = ptr[13];
   97         d->p_cpg = g_dec_le2(ptr + 14);
   98 }
   99 
  100 static void
  101 g_bsd_ledec_disklabel(u_char *ptr, struct disklabel *d)
  102 {
  103         int i;
  104 
  105         d->d_magic = g_dec_le4(ptr + 0);
  106         d->d_type = g_dec_le2(ptr + 4);
  107         d->d_subtype = g_dec_le2(ptr + 6);
  108         bcopy(ptr + 8, d->d_typename, 16);
  109         bcopy(ptr + 24, d->d_packname, 16);
  110         d->d_secsize = g_dec_le4(ptr + 40);
  111         d->d_nsectors = g_dec_le4(ptr + 44);
  112         d->d_ntracks = g_dec_le4(ptr + 48);
  113         d->d_ncylinders = g_dec_le4(ptr + 52);
  114         d->d_secpercyl = g_dec_le4(ptr + 56);
  115         d->d_secperunit = g_dec_le4(ptr + 60);
  116         d->d_sparespertrack = g_dec_le2(ptr + 64);
  117         d->d_sparespercyl = g_dec_le2(ptr + 66);
  118         d->d_acylinders = g_dec_le4(ptr + 68);
  119         d->d_rpm = g_dec_le2(ptr + 72);
  120         d->d_interleave = g_dec_le2(ptr + 74);
  121         d->d_trackskew = g_dec_le2(ptr + 76);
  122         d->d_cylskew = g_dec_le2(ptr + 78);
  123         d->d_headswitch = g_dec_le4(ptr + 80);
  124         d->d_trkseek = g_dec_le4(ptr + 84);
  125         d->d_flags = g_dec_le4(ptr + 88);
  126         d->d_drivedata[0] = g_dec_le4(ptr + 92);
  127         d->d_drivedata[1] = g_dec_le4(ptr + 96);
  128         d->d_drivedata[2] = g_dec_le4(ptr + 100);
  129         d->d_drivedata[3] = g_dec_le4(ptr + 104);
  130         d->d_drivedata[4] = g_dec_le4(ptr + 108);
  131         d->d_spare[0] = g_dec_le4(ptr + 112);
  132         d->d_spare[1] = g_dec_le4(ptr + 116);
  133         d->d_spare[2] = g_dec_le4(ptr + 120);
  134         d->d_spare[3] = g_dec_le4(ptr + 124);
  135         d->d_spare[4] = g_dec_le4(ptr + 128);
  136         d->d_magic2 = g_dec_le4(ptr + 132);
  137         d->d_checksum = g_dec_le2(ptr + 136);
  138         d->d_npartitions = g_dec_le2(ptr + 138);
  139         d->d_bbsize = g_dec_le4(ptr + 140);
  140         d->d_sbsize = g_dec_le4(ptr + 144);
  141         for (i = 0; i < MAXPARTITIONS; i++)
  142                 g_bsd_ledec_partition(ptr + 148 + 16 * i, &d->d_partitions[i]);
  143 }
  144 
  145 static void
  146 g_bsd_leenc_partition(u_char *ptr, struct partition *d)
  147 {
  148         g_enc_le4(ptr + 0, d->p_size);
  149         g_enc_le4(ptr + 4, d->p_offset);
  150         g_enc_le4(ptr + 8, d->p_fsize);
  151         ptr[12] = d->p_fstype;
  152         ptr[13] = d->p_frag;
  153         g_enc_le2(ptr + 14, d->p_cpg);
  154 }
  155 
  156 static void
  157 g_bsd_leenc_disklabel(u_char *ptr, struct disklabel *d)
  158 {
  159         int i;
  160 
  161         g_enc_le4(ptr + 0, d->d_magic);
  162         g_enc_le2(ptr + 4, d->d_type);
  163         g_enc_le2(ptr + 6, d->d_subtype);
  164         bcopy(d->d_typename, ptr + 8, 16);
  165         bcopy(d->d_packname, ptr + 24, 16);
  166         g_enc_le4(ptr + 40, d->d_secsize);
  167         g_enc_le4(ptr + 44, d->d_nsectors);
  168         g_enc_le4(ptr + 48, d->d_ntracks);
  169         g_enc_le4(ptr + 52, d->d_ncylinders);
  170         g_enc_le4(ptr + 56, d->d_secpercyl);
  171         g_enc_le4(ptr + 60, d->d_secperunit);
  172         g_enc_le2(ptr + 64, d->d_sparespertrack);
  173         g_enc_le2(ptr + 66, d->d_sparespercyl);
  174         g_enc_le4(ptr + 68, d->d_acylinders);
  175         g_enc_le2(ptr + 72, d->d_rpm);
  176         g_enc_le2(ptr + 74, d->d_interleave);
  177         g_enc_le2(ptr + 76, d->d_trackskew);
  178         g_enc_le2(ptr + 78, d->d_cylskew);
  179         g_enc_le4(ptr + 80, d->d_headswitch);
  180         g_enc_le4(ptr + 84, d->d_trkseek);
  181         g_enc_le4(ptr + 88, d->d_flags);
  182         g_enc_le4(ptr + 92, d->d_drivedata[0]);
  183         g_enc_le4(ptr + 96, d->d_drivedata[1]);
  184         g_enc_le4(ptr + 100, d->d_drivedata[2]);
  185         g_enc_le4(ptr + 104, d->d_drivedata[3]);
  186         g_enc_le4(ptr + 108, d->d_drivedata[4]);
  187         g_enc_le4(ptr + 112, d->d_spare[0]);
  188         g_enc_le4(ptr + 116, d->d_spare[1]);
  189         g_enc_le4(ptr + 120, d->d_spare[2]);
  190         g_enc_le4(ptr + 124, d->d_spare[3]);
  191         g_enc_le4(ptr + 128, d->d_spare[4]);
  192         g_enc_le4(ptr + 132, d->d_magic2);
  193         g_enc_le2(ptr + 136, d->d_checksum);
  194         g_enc_le2(ptr + 138, d->d_npartitions);
  195         g_enc_le4(ptr + 140, d->d_bbsize);
  196         g_enc_le4(ptr + 144, d->d_sbsize);
  197         for (i = 0; i < MAXPARTITIONS; i++)
  198                 g_bsd_leenc_partition(ptr + 148 + 16 * i, &d->d_partitions[i]);
  199 }
  200 
  201 static int
  202 g_bsd_ondisk_size(void)
  203 {
  204         return (148 + 16 * MAXPARTITIONS);
  205 }
  206 
  207 /*
  208  * For reasons which were valid and just in their days, FreeBSD/i386 uses
  209  * absolute disk-addresses in disklabels.  The way it works is that the
  210  * p_offset field of all partitions have the first sector number of the
  211  * disk slice added to them.  This was hidden kernel-magic, userland did
  212  * not see these offsets.  These two functions subtract and add them
  213  * while converting from the "ondisk" to the "inram" labels and vice
  214  * versa.
  215  */
  216 static void
  217 ondisk2inram(struct g_bsd_softc *sc)
  218 {
  219         struct partition *ppp;
  220         struct disklabel *dl;
  221         int i;
  222 
  223         sc->inram = sc->ondisk;
  224         dl = &sc->inram;
  225 
  226         /* Basic sanity-check needed to avoid mistakes. */
  227         if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC)
  228                 return;
  229         if (dl->d_npartitions > MAXPARTITIONS)
  230                 return;
  231 
  232         sc->rawoffset = dl->d_partitions[RAW_PART].p_offset;
  233         for (i = 0; i < dl->d_npartitions; i++) {
  234                 ppp = &dl->d_partitions[i];
  235                 if (ppp->p_size != 0 && ppp->p_offset < sc->rawoffset)
  236                         sc->rawoffset = 0;
  237         }
  238         if (sc->rawoffset > 0) {
  239                 for (i = 0; i < dl->d_npartitions; i++) {
  240                         ppp = &dl->d_partitions[i];
  241                         if (ppp->p_offset != 0)
  242                                 ppp->p_offset -= sc->rawoffset;
  243                 }
  244         }
  245         dl->d_checksum = 0;
  246         dl->d_checksum = dkcksum(&sc->inram);
  247 }
  248 
  249 static void
  250 inram2ondisk(struct g_bsd_softc *sc)
  251 {
  252         struct partition *ppp;
  253         int i;
  254 
  255         sc->ondisk = sc->inram;
  256         if (sc->mbroffset != 0)
  257                 sc->rawoffset = sc->mbroffset / sc->inram.d_secsize; 
  258         if (sc->rawoffset != 0) {
  259                 for (i = 0; i < sc->inram.d_npartitions; i++) {
  260                         ppp = &sc->ondisk.d_partitions[i];
  261                         if (ppp->p_size > 0) 
  262                                 ppp->p_offset += sc->rawoffset;
  263                         else
  264                                 ppp->p_offset = 0;
  265                 }
  266         }
  267         sc->ondisk.d_checksum = 0;
  268         sc->ondisk.d_checksum = dkcksum(&sc->ondisk);
  269 }
  270 
  271 /*
  272  * Check that this looks like a valid disklabel, but be prepared
  273  * to get any kind of junk.  The checksum must be checked only
  274  * after this function returns success to prevent a bogus d_npartitions
  275  * value from tripping us up.
  276  */
  277 static int
  278 g_bsd_checklabel(struct disklabel *dl)
  279 {
  280         struct partition *ppp;
  281         int i;
  282 
  283         if (dl->d_magic != DISKMAGIC || dl->d_magic2 != DISKMAGIC)
  284                 return (EINVAL);
  285         /*
  286          * If the label specifies more partitions than we can handle
  287          * we have to reject it:  If people updated the label they would
  288          * trash it, and that would break the checksum.
  289          */
  290         if (dl->d_npartitions > MAXPARTITIONS)
  291                 return (EINVAL);
  292 
  293         for (i = 0; i < dl->d_npartitions; i++) {
  294                 ppp = &dl->d_partitions[i];
  295                 /* Cannot extend past unit. */
  296                 if (ppp->p_size != 0 &&
  297                      ppp->p_offset + ppp->p_size > dl->d_secperunit) {
  298                         return (EINVAL);
  299                 }
  300         }
  301         return (0);
  302 }
  303 
  304 /*
  305  * Modify our slicer to match proposed disklabel, if possible.
  306  * First carry out all the simple checks, then lock topology
  307  * and check that no open providers are affected negatively
  308  * then carry out all the changes.
  309  *
  310  * NB: Returns with topology held only if successful return.
  311  */
  312 static int
  313 g_bsd_modify(struct g_geom *gp, struct disklabel *dl)
  314 {
  315         int i, error;
  316         struct partition *ppp;
  317         struct g_slicer *gsp;
  318         struct g_consumer *cp;
  319         u_int secsize, u;
  320         off_t mediasize;
  321 
  322         /* Basic check that this is indeed a disklabel. */
  323         error = g_bsd_checklabel(dl);
  324         if (error)
  325                 return (error);
  326 
  327         /* Make sure the checksum is OK. */
  328         if (dkcksum(dl) != 0)
  329                 return (EINVAL);
  330 
  331         /* Get dimensions of our device. */
  332         cp = LIST_FIRST(&gp->consumer);
  333         secsize = cp->provider->sectorsize;
  334         mediasize = cp->provider->mediasize;
  335 
  336 #ifdef nolonger
  337         /*
  338          * The raw-partition must start at zero.  We do not check that the
  339          * size == mediasize because this is overly restrictive.  We have
  340          * already tested in g_bsd_checklabel() that it is not longer.
  341          * XXX: RAW_PART is archaic anyway, and we should drop it.
  342          */
  343         if (dl->d_partitions[RAW_PART].p_offset != 0)
  344                 return (EINVAL);
  345 #endif
  346 
  347 #ifdef notyet
  348         /*
  349          * Indications are that the d_secperunit is not correctly
  350          * initialized in many cases, and since we don't need it
  351          * for anything, we dont strictly need this test.
  352          * Preemptive action to avoid confusing people in disklabel(8)
  353          * may be in order.
  354          */
  355         /* The label cannot claim a larger size than the media. */
  356         if ((off_t)dl->d_secperunit * dl->d_secsize > mediasize)
  357                 return (EINVAL);
  358 #endif
  359 
  360 
  361         /* ... or a smaller sector size. */
  362         if (dl->d_secsize < secsize)
  363                 return (EINVAL);
  364 
  365         /* ... or a non-multiple sector size. */
  366         if (dl->d_secsize % secsize != 0)
  367                 return (EINVAL);
  368 
  369         g_topology_lock();
  370 
  371         /* Don't munge open partitions. */
  372         gsp = gp->softc;
  373         for (i = 0; i < dl->d_npartitions; i++) {
  374                 ppp = &dl->d_partitions[i];
  375 
  376                 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
  377                     (off_t)ppp->p_offset * dl->d_secsize,
  378                     (off_t)ppp->p_size * dl->d_secsize,
  379                      dl->d_secsize,
  380                     "%s%c", gp->name, 'a' + i);
  381                 if (error) {
  382                         g_topology_unlock();
  383                         return (error);
  384                 }
  385         }
  386 
  387         /* Look good, go for it... */
  388         for (u = 0; u < gsp->nslice; u++) {
  389                 ppp = &dl->d_partitions[u];
  390                 g_slice_config(gp, u, G_SLICE_CONFIG_SET,
  391                     (off_t)ppp->p_offset * dl->d_secsize,
  392                     (off_t)ppp->p_size * dl->d_secsize,
  393                      dl->d_secsize,
  394                     "%s%c", gp->name, 'a' + u);
  395         }
  396         return (0);
  397 }
  398 
  399 /*
  400  * Calculate a disklabel checksum for a little-endian byte-stream.
  401  * We need access to the decoded disklabel because the checksum only
  402  * covers the partition data for the first d_npartitions.
  403  */
  404 static int
  405 g_bsd_lesum(struct disklabel *dl, u_char *p)
  406 {
  407         u_char *pe;
  408         uint16_t sum;
  409 
  410         pe = p + 148 + 16 * dl->d_npartitions;
  411         sum = 0;
  412         while (p < pe) {
  413                 sum ^= g_dec_le2(p);
  414                 p += 2;
  415         }
  416         return (sum);
  417 }
  418 
  419 /*
  420  * This is an internal helper function, called multiple times from the taste
  421  * function to try to locate a disklabel on the disk.  More civilized formats
  422  * will not need this, as there is only one possible place on disk to look
  423  * for the magic spot.
  424  */
  425 
  426 static int
  427 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)
  428 {
  429         int error;
  430         u_char *buf;
  431         struct disklabel *dl;
  432         off_t secoff;
  433 
  434         /*
  435          * We need to read entire aligned sectors, and we assume that the
  436          * disklabel does not span sectors, so one sector is enough.
  437          */
  438         error = 0;
  439         secoff = offset % secsize;
  440         buf = g_read_data(cp, offset - secoff, secsize, &error);
  441         if (buf == NULL || error != 0)
  442                 return (ENOENT);
  443 
  444         /* Decode into our native format. */
  445         dl = &ms->ondisk;
  446         g_bsd_ledec_disklabel(buf + secoff, dl);
  447 
  448         ondisk2inram(ms);
  449 
  450         dl = &ms->inram;
  451         /* Does it look like a label at all? */
  452         if (g_bsd_checklabel(dl))
  453                 error = ENOENT;
  454         /* ... and does the raw data have a good checksum? */
  455         if (error == 0 && g_bsd_lesum(dl, buf + secoff) != 0)
  456                 error = ENOENT;
  457 
  458         /* Remember to free the buffer g_read_data() gave us. */
  459         g_free(buf);
  460 
  461         /* If we had a label, record it properly. */
  462         if (error == 0) {
  463                 gsp->frontstuff = 16 * secsize; /* XXX */
  464                 ms->labeloffset = offset;
  465                 g_topology_lock();
  466                 g_slice_conf_hot(gp, 0, offset, g_bsd_ondisk_size());
  467                 g_topology_unlock();
  468         }
  469         return (error);
  470 }
  471 
  472 /*
  473  * Implement certain ioctls to modify disklabels with.  This function
  474  * is called by the event handler thread with topology locked as result
  475  * of the g_call_me() in g_bsd_start().  It is not necessary to keep
  476  * topology locked all the time but make sure to return with topology
  477  * locked as well.
  478  */
  479 
  480 static void
  481 g_bsd_ioctl(void *arg)
  482 {
  483         struct bio *bp;
  484         struct g_geom *gp;
  485         struct g_slicer *gsp;
  486         struct g_bsd_softc *ms;
  487         struct disklabel *dl;
  488         struct g_ioctl *gio;
  489         struct g_consumer *cp;
  490         u_char *buf;
  491         off_t secoff;
  492         u_int secsize;
  493         int error, i;
  494         uint64_t sum;
  495 
  496         /* We don't need topology for now. */
  497         g_topology_unlock();
  498 
  499         /* Get hold of the interesting bits from the bio. */
  500         bp = arg;
  501         gp = bp->bio_to->geom;
  502         gsp = gp->softc;
  503         ms = gsp->softc;
  504         gio = (struct g_ioctl *)bp->bio_data;
  505 
  506         /* The disklabel to set is the ioctl argument. */
  507         dl = gio->data;
  508 
  509         /* Validate and modify our slice instance to match. */
  510         error = g_bsd_modify(gp, dl);   /* Picks up topology lock on success. */
  511         if (error) {
  512                 g_topology_lock();
  513                 g_io_deliver(bp, error);
  514                 return;
  515         }
  516         /* Update our copy of the disklabel. */
  517         ms->inram = *dl;
  518         inram2ondisk(ms);
  519 
  520         if (gio->cmd == DIOCSDINFO) {
  521                 g_io_deliver(bp, 0);
  522                 return;
  523         }
  524         KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl"));
  525         cp = LIST_FIRST(&gp->consumer);
  526         /* Get sector size, we need it to read data. */
  527         secsize = cp->provider->sectorsize;
  528         secoff = ms->labeloffset % secsize;
  529         buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error);
  530         if (buf == NULL || error != 0) {
  531                 g_io_deliver(bp, error);
  532                 return;
  533         }
  534         dl = &ms->ondisk;
  535         g_bsd_leenc_disklabel(buf + secoff, dl);
  536         if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
  537                 sum = 0;
  538                 for (i = 0; i < 63; i++)
  539                         sum += g_dec_le8(buf + i * 8);
  540                 g_enc_le8(buf + 504, sum);
  541         }
  542         error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize);
  543         g_free(buf);
  544         g_io_deliver(bp, error);
  545 }
  546 
  547 /*
  548  * If the user tries to overwrite our disklabel through an open partition
  549  * or via a magicwrite config call, we end up here and try to prevent
  550  * footshooting as best we can.
  551  */
  552 static void
  553 g_bsd_hotwrite(void *arg)
  554 {
  555         struct bio *bp;
  556         struct g_geom *gp;
  557         struct g_slicer *gsp;
  558         struct g_slice *gsl;
  559         struct g_bsd_softc *ms;
  560         struct g_bsd_softc fake;
  561         u_char *p;
  562         int error;
  563         
  564         bp = arg;
  565         gp = bp->bio_to->geom;
  566         gsp = gp->softc;
  567         ms = gsp->softc;
  568         gsl = &gsp->slices[bp->bio_to->index];
  569         p = (u_char*)bp->bio_data + ms->labeloffset 
  570             - (bp->bio_offset + gsl->offset);
  571         g_bsd_ledec_disklabel(p, &fake.ondisk);
  572         
  573         ondisk2inram(&fake);
  574         if (g_bsd_checklabel(&fake.inram)) {
  575                 g_io_deliver(bp, EPERM);
  576                 return;
  577         }
  578         if (g_bsd_lesum(&fake.ondisk, p) != 0) {
  579                 g_io_deliver(bp, EPERM);
  580                 return;
  581         }
  582         g_topology_unlock();
  583         error = g_bsd_modify(gp, &fake.inram);  /* May pick up topology. */
  584         if (error) {
  585                 g_io_deliver(bp, EPERM);
  586                 g_topology_lock();
  587                 return;
  588         }
  589         /* Update our copy of the disklabel. */
  590         ms->inram = fake.inram;
  591         inram2ondisk(ms);
  592         g_bsd_leenc_disklabel(p, &ms->ondisk);
  593         g_slice_finish_hot(bp);
  594 }
  595 
  596 /*-
  597  * This start routine is only called for non-trivial requests, all the
  598  * trivial ones are handled autonomously by the slice code.
  599  * For requests we handle here, we must call the g_io_deliver() on the
  600  * bio, and return non-zero to indicate to the slice code that we did so.
  601  * This code executes in the "DOWN" I/O path, this means:
  602  *    * No sleeping.
  603  *    * Don't grab the topology lock.
  604  *    * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
  605  */
  606 
  607 static int
  608 g_bsd_start(struct bio *bp)
  609 {
  610         struct g_geom *gp;
  611         struct g_bsd_softc *ms;
  612         struct g_slicer *gsp;
  613         struct g_ioctl *gio;
  614         int error;
  615 
  616         gp = bp->bio_to->geom;
  617         gsp = gp->softc;
  618         ms = gsp->softc;
  619         switch(bp->bio_cmd) {
  620         case BIO_READ:
  621                 /* We allow reading of our hot spots */
  622                 return (0);
  623         case BIO_DELETE:
  624                 /* We do not allow deleting our hot spots */
  625                 return (EPERM);
  626         case BIO_WRITE:
  627                 g_call_me(g_bsd_hotwrite, bp);
  628                 return (EJUSTRETURN);
  629         case BIO_GETATTR:
  630         case BIO_SETATTR:
  631                 break;
  632         default:
  633                 KASSERT(0 == 1, ("Unknown bio_cmd in g_bsd_start (%d)",
  634                     bp->bio_cmd));
  635         }
  636 
  637         /* We only handle ioctl(2) requests of the right format. */
  638         if (strcmp(bp->bio_attribute, "GEOM::ioctl"))
  639                 return (0);
  640         else if (bp->bio_length != sizeof(*gio))
  641                 return (0);
  642 
  643         /* Get hold of the ioctl parameters. */
  644         gio = (struct g_ioctl *)bp->bio_data;
  645 
  646         switch (gio->cmd) {
  647         case DIOCGDINFO:
  648                 /* Return a copy of the disklabel to userland. */
  649                 bcopy(&ms->inram, gio->data, sizeof(ms->inram));
  650                 g_io_deliver(bp, 0);
  651                 return (1);
  652         case DIOCSDINFO:
  653         case DIOCWDINFO:
  654                 /*
  655                  * These we cannot do without the topology lock and some
  656                  * some I/O requests.  Ask the event-handler to schedule
  657                  * us in a less restricted environment.
  658                  */
  659                 error = g_call_me(g_bsd_ioctl, bp);
  660                 if (error)
  661                         g_io_deliver(bp, error);
  662                 /*
  663                  * We must return non-zero to indicate that we will deal
  664                  * with this bio, even though we have not done so yet.
  665                  */
  666                 return (1);
  667         default:
  668                 return (0);
  669         }
  670 }
  671 
  672 /*
  673  * Dump configuration information in XML format.
  674  * Notice that the function is called once for the geom and once for each
  675  * consumer and provider.  We let g_slice_dumpconf() do most of the work.
  676  */
  677 static void
  678 g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
  679 {
  680         struct g_bsd_softc *ms;
  681         struct g_slicer *gsp;
  682 
  683         gsp = gp->softc;
  684         ms = gsp->softc;
  685         g_slice_dumpconf(sb, indent, gp, cp, pp);
  686         if (indent != NULL && pp == NULL && cp == NULL) {
  687                 sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n",
  688                     indent, (intmax_t)ms->labeloffset);
  689                 sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n",
  690                     indent, (intmax_t)ms->rawoffset);
  691                 sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n",
  692                     indent, (intmax_t)ms->mbroffset);
  693         } else if (pp != NULL) {
  694                 if (indent == NULL)
  695                         sbuf_printf(sb, " ty %d",
  696                             ms->inram.d_partitions[pp->index].p_fstype);
  697                 else
  698                         sbuf_printf(sb, "%s<type>%d</type>\n", indent,
  699                             ms->inram.d_partitions[pp->index].p_fstype);
  700         }
  701 }
  702 
  703 /*
  704  * The taste function is called from the event-handler, with the topology
  705  * lock already held and a provider to examine.  The flags are unused.
  706  *
  707  * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and
  708  * if we find valid, consistent magic on it, build a geom on it.
  709  * any magic bits which indicate that we should automatically put a BSD
  710  * geom on it.
  711  *
  712  * There may be cases where the operator would like to put a BSD-geom on
  713  * providers which do not meet all of the requirements.  This can be done
  714  * by instead passing the G_TF_INSIST flag, which will override these
  715  * checks.
  716  *
  717  * The final flags value is G_TF_TRANSPARENT, which instructs the method
  718  * to put a geom on top of the provider and configure it to be as transparent
  719  * as possible.  This is not really relevant to the BSD method and therefore
  720  * not implemented here.
  721  */
  722 
  723 static struct g_geom *
  724 g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags)
  725 {
  726         struct g_geom *gp;
  727         struct g_consumer *cp;
  728         int error, i;
  729         struct g_bsd_softc *ms;
  730         struct disklabel *dl;
  731         u_int secsize;
  732         struct g_slicer *gsp;
  733 
  734         g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name);
  735         g_topology_assert();
  736 
  737         /* We don't implement transparent inserts. */
  738         if (flags == G_TF_TRANSPARENT)
  739                 return (NULL);
  740 
  741         /*
  742          * The BSD-method will not automatically configure itself recursively
  743          * Note that it is legal to examine the class-name of our provider,
  744          * nothing else should ever be examined inside the provider.
  745          */
  746         if (flags == G_TF_NORMAL &&
  747             !strcmp(pp->geom->class->name, BSD_CLASS_NAME))
  748                 return (NULL);
  749 
  750         /*
  751          * BSD labels are a subclass of the general "slicing" topology so
  752          * a lot of the work can be done by the common "slice" code.
  753          * Create a geom with space for MAXPARTITIONS providers, one consumer
  754          * and a softc structure for us.  Specify the provider to attach
  755          * the consumer to and our "start" routine for special requests.
  756          * The provider is opened with mode (1,0,0) so we can do reads
  757          * from it.
  758          */
  759         gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms,
  760              sizeof(*ms), g_bsd_start);
  761         if (gp == NULL)
  762                 return (NULL);
  763 
  764         /*
  765          * Now that we have attached to and opened our provider, we do
  766          * not need the topology lock until we change the topology again
  767          * next time.
  768          */
  769         g_topology_unlock();
  770 
  771         /*
  772          * Fill in the optional details, in our case we have a dumpconf
  773          * routine which the "slice" code should call at the right time
  774          */
  775         gp->dumpconf = g_bsd_dumpconf;
  776 
  777         /* Get the geom_slicer softc from the geom. */
  778         gsp = gp->softc;
  779 
  780         /*
  781          * The do...while loop here allows us to have multiple escapes
  782          * using a simple "break".  This improves code clarity without
  783          * ending up in deep nesting and without using goto or come from.
  784          */
  785         do {
  786                 /*
  787                  * If the provider is an MBR we will only auto attach
  788                  * to type 165 slices in the G_TF_NORMAL case.  We will
  789                  * attach to any other type (BSD was handles above)
  790                  */
  791                 error = g_getattr("MBR::type", cp, &i);
  792                 if (!error) {
  793                         if (i != 165 && flags == G_TF_NORMAL)
  794                                 break;
  795                         error = g_getattr("MBR::offset", cp, &ms->mbroffset);
  796                         if (error)
  797                                 break;
  798                 }
  799 
  800                 /* Same thing if we are inside a PC98 */
  801                 error = g_getattr("PC98::type", cp, &i);
  802                 if (!error) {
  803                         if (i != 0xc494 && flags == G_TF_NORMAL)
  804                                 break;
  805                         error = g_getattr("PC98::offset", cp, &ms->mbroffset);
  806                         if (error)
  807                                 break;
  808                 }
  809 
  810                 /* Get sector size, we need it to read data. */
  811                 secsize = cp->provider->sectorsize;
  812                 if (secsize < 512)
  813                         break;
  814 
  815                 /* First look for a label at the start of the second sector. */
  816                 error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize);
  817 
  818                 /* Next, look for alpha labels */
  819                 if (error)
  820                         error = g_bsd_try(gp, gsp, cp, secsize, ms,
  821                             ALPHA_LABEL_OFFSET);
  822 
  823                 /* If we didn't find a label, punt. */
  824                 if (error)
  825                         break;
  826 
  827                 /*
  828                  * Process the found disklabel, and modify our "slice"
  829                  * instance to match it, if possible.
  830                  */
  831                 dl = &ms->inram;
  832                 error = g_bsd_modify(gp, dl);   /* Picks up topology lock. */
  833                 if (!error)
  834                         g_topology_unlock();
  835                 break;
  836         } while (0);
  837 
  838         /* Success of failure, we can close our provider now. */
  839         g_topology_lock();
  840         error = g_access_rel(cp, -1, 0, 0);
  841 
  842         /* If we have configured any providers, return the new geom. */
  843         if (gsp->nprovider > 0)
  844                 return (gp);
  845         /*
  846          * ...else push the "self-destruct" button, by spoiling our own
  847          * consumer.  This triggers a call to g_std_spoiled which will
  848          * dismantle what was setup.
  849          */
  850         g_std_spoiled(cp);
  851         return (NULL);
  852 }
  853 
  854 /* Finally, register with GEOM infrastructure. */
  855 static struct g_class g_bsd_class = {
  856         BSD_CLASS_NAME,
  857         g_bsd_taste,
  858         NULL,
  859         G_CLASS_INITIALIZER
  860 };
  861 
  862 DECLARE_GEOM_CLASS(g_bsd_class, g_bsd);

Cache object: 5f497a05b9e4fbe8c6bdb3074bd88ea5


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