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/kern/subr_diskslice.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) 1994 Bruce D. Evans.
    3  * All rights reserved.
    4  *
    5  * Copyright (c) 1990 The Regents of the University of California.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to Berkeley by
    9  * William Jolitz.
   10  *
   11  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
   12  * All rights reserved.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  * 3. All advertising materials mentioning features or use of this software
   23  *    must display the following acknowledgement:
   24  *      This product includes software developed by the University of
   25  *      California, Berkeley and its contributors.
   26  * 4. Neither the name of the University nor the names of its contributors
   27  *    may be used to endorse or promote products derived from this software
   28  *    without specific prior written permission.
   29  *
   30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   40  * SUCH DAMAGE.
   41  *
   42  *      from: @(#)wd.c  7.2 (Berkeley) 5/9/91
   43  *      from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $
   44  *      from: @(#)ufs_disksubr.c        7.16 (Berkeley) 5/4/91
   45  *      from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $
   46  * $FreeBSD: releng/5.0/sys/kern/subr_diskslice.c 105354 2002-10-17 20:03:38Z robert $
   47  */
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/bio.h>
   52 #include <sys/conf.h>
   53 #include <sys/disk.h>
   54 #include <sys/disklabel.h>
   55 #include <sys/diskslice.h>
   56 #if defined(PC98) && !defined(PC98_ATCOMPAT)
   57 #include <sys/diskpc98.h>
   58 #else
   59 #include <sys/diskmbr.h>
   60 #endif
   61 #include <sys/fcntl.h>
   62 #include <sys/malloc.h>
   63 #include <sys/stat.h>
   64 #include <sys/stdint.h>
   65 #include <sys/syslog.h>
   66 #include <sys/vnode.h>
   67 
   68 #define TRACE(str)      do { if (ds_debug) printf str; } while (0)
   69 
   70 typedef u_char  bool_t;
   71 
   72 static volatile bool_t ds_debug;
   73 
   74 static struct disklabel *clone_label(struct disklabel *lp);
   75 static void dsiodone(struct bio *bp);
   76 static char *fixlabel(char *sname, struct diskslice *sp,
   77                            struct disklabel *lp, int writeflag);
   78 static void free_ds_label(struct diskslices *ssp, int slice);
   79 static void partition_info(char *sname, int part, struct partition *pp);
   80 static void slice_info(char *sname, struct diskslice *sp);
   81 static void set_ds_label(struct diskslices *ssp, int slice,
   82                               struct disklabel *lp);
   83 static void set_ds_labeldevs(dev_t dev, struct diskslices *ssp);
   84 static void set_ds_wlabel(struct diskslices *ssp, int slice,
   85                                int wlabel);
   86 
   87 /*
   88  * Duplicate a label for the whole disk, and initialize defaults in the
   89  * copy for fields that are not already initialized.  The caller only
   90  * needs to initialize d_secsize and d_secperunit, and zero the fields
   91  * that are to be defaulted.
   92  */
   93 static struct disklabel *
   94 clone_label(lp)
   95         struct disklabel *lp;
   96 {
   97         struct disklabel *lp1;
   98 
   99         lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK);
  100         *lp1 = *lp;
  101         lp = NULL;
  102         if (lp1->d_typename[0] == '\0')
  103                 strlcpy(lp1->d_typename, "amnesiac", sizeof(lp1->d_typename));
  104         if (lp1->d_packname[0] == '\0')
  105                 strlcpy(lp1->d_packname, "fictitious", sizeof(lp1->d_packname));
  106         if (lp1->d_nsectors == 0)
  107                 lp1->d_nsectors = 32;
  108         if (lp1->d_ntracks == 0)
  109                 lp1->d_ntracks = 64;
  110         lp1->d_secpercyl = lp1->d_nsectors * lp1->d_ntracks;
  111         lp1->d_ncylinders = lp1->d_secperunit / lp1->d_secpercyl;
  112         if (lp1->d_rpm == 0)
  113                 lp1->d_rpm = 3600;
  114         if (lp1->d_interleave == 0)
  115                 lp1->d_interleave = 1;
  116         if (lp1->d_npartitions < RAW_PART + 1)
  117                 lp1->d_npartitions = MAXPARTITIONS;
  118         if (lp1->d_bbsize == 0)
  119                 lp1->d_bbsize = BBSIZE;
  120         lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit;
  121         lp1->d_magic = DISKMAGIC;
  122         lp1->d_magic2 = DISKMAGIC;
  123         lp1->d_checksum = dkcksum(lp1);
  124         return (lp1);
  125 }
  126 
  127 dev_t
  128 dkmodpart(dev_t dev, int part)
  129 {
  130         return (makedev(major(dev), (minor(dev) & ~7) | part));
  131 }
  132 
  133 dev_t
  134 dkmodslice(dev_t dev, int slice)
  135 {
  136         return (makedev(major(dev), (minor(dev) & ~0x1f0000) | (slice << 16)));
  137 }
  138 
  139 u_int
  140 dkunit(dev_t dev)
  141 {
  142         return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f));
  143 }
  144 
  145 /*
  146  * Determine the size of the transfer, and make sure it is
  147  * within the boundaries of the partition. Adjust transfer
  148  * if needed, and signal errors or early completion.
  149  *
  150  * XXX TODO:
  151  *      o Split buffers that are too big for the device.
  152  *      o Check for overflow.
  153  *      o Finish cleaning this up.
  154  */
  155 int
  156 dscheck(bp, ssp)
  157         struct bio *bp;
  158         struct diskslices *ssp;
  159 {
  160         daddr_t blkno;
  161         daddr_t endsecno;
  162         daddr_t labelsect;
  163         struct disklabel *lp;
  164         char *msg;
  165         long    nsec;
  166         struct partition *pp;
  167         daddr_t secno;
  168         daddr_t slicerel_secno;
  169         struct diskslice *sp;
  170 
  171         blkno = bp->bio_blkno;
  172         if (blkno < 0) {
  173                 printf("dscheck(%s): negative bio_blkno %ld\n", 
  174                     devtoname(bp->bio_dev), (long)blkno);
  175                 bp->bio_error = EINVAL;
  176                 goto bad;
  177         }
  178         sp = &ssp->dss_slices[dkslice(bp->bio_dev)];
  179         lp = sp->ds_label;
  180         if (ssp->dss_secmult == 1) {
  181                 if (bp->bio_bcount % (u_long)DEV_BSIZE)
  182                         goto bad_bcount;
  183                 secno = blkno;
  184                 nsec = bp->bio_bcount >> DEV_BSHIFT;
  185         } else if (ssp->dss_secshift != -1) {
  186                 if (bp->bio_bcount & (ssp->dss_secsize - 1))
  187                         goto bad_bcount;
  188                 if (blkno & (ssp->dss_secmult - 1))
  189                         goto bad_blkno;
  190                 secno = blkno >> ssp->dss_secshift;
  191                 nsec = bp->bio_bcount >> (DEV_BSHIFT + ssp->dss_secshift);
  192         } else {
  193                 if (bp->bio_bcount % ssp->dss_secsize)
  194                         goto bad_bcount;
  195                 if (blkno % ssp->dss_secmult)
  196                         goto bad_blkno;
  197                 secno = blkno / ssp->dss_secmult;
  198                 nsec = bp->bio_bcount / ssp->dss_secsize;
  199         }
  200         if (lp == NULL) {
  201                 labelsect = -LABELSECTOR - 1;
  202                 endsecno = sp->ds_size;
  203                 slicerel_secno = secno;
  204         } else {
  205                 labelsect = lp->d_partitions[LABEL_PART].p_offset;
  206 if (labelsect != 0) Debugger("labelsect != 0 in dscheck()");
  207                 pp = &lp->d_partitions[dkpart(bp->bio_dev)];
  208                 endsecno = pp->p_size;
  209                 slicerel_secno = pp->p_offset + secno;
  210         }
  211 
  212         /* overwriting disk label ? */
  213         /* XXX should also protect bootstrap in first 8K */
  214         if (slicerel_secno <= LABELSECTOR + labelsect &&
  215 #if LABELSECTOR != 0
  216             slicerel_secno + nsec > LABELSECTOR + labelsect &&
  217 #endif
  218             (bp->bio_cmd == BIO_WRITE) && sp->ds_wlabel == 0) {
  219                 bp->bio_error = EROFS;
  220                 goto bad;
  221         }
  222 
  223 #if defined(DOSBBSECTOR) && defined(notyet)
  224         /* overwriting master boot record? */
  225         if (slicerel_secno <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) &&
  226             sp->ds_wlabel == 0) {
  227                 bp->bio_error = EROFS;
  228                 goto bad;
  229         }
  230 #endif
  231 
  232         /* beyond partition? */
  233         if ((uintmax_t)secno + nsec > endsecno) {
  234                 /* if exactly at end of disk, return an EOF */
  235                 if (secno == endsecno) {
  236                         bp->bio_resid = bp->bio_bcount;
  237                         return (0);
  238                 }
  239                 /* or truncate if part of it fits */
  240                 if (secno > endsecno) {
  241                         bp->bio_error = EINVAL;
  242                         goto bad;
  243                 }
  244                 bp->bio_bcount = (endsecno - secno) * ssp->dss_secsize;
  245         }
  246 
  247         bp->bio_pblkno = sp->ds_offset + slicerel_secno;
  248 
  249         /*
  250          * Snoop on label accesses if the slice offset is nonzero.  Fudge
  251          * offsets in the label to keep the in-core label coherent with
  252          * the on-disk one.
  253          */
  254         if (slicerel_secno <= LABELSECTOR + labelsect
  255 #if LABELSECTOR != 0
  256             && slicerel_secno + nsec > LABELSECTOR + labelsect
  257 #endif
  258             && sp->ds_offset != 0) {
  259                 struct iodone_chain *ic;
  260 
  261                 ic = malloc(sizeof *ic , M_DEVBUF, M_WAITOK);
  262                 ic->ic_prev_flags = bp->bio_flags;
  263                 ic->ic_prev_iodone = bp->bio_done;
  264                 ic->ic_prev_iodone_chain = bp->bio_done_chain;
  265                 ic->ic_args[0].ia_long = (LABELSECTOR + labelsect -
  266                     slicerel_secno) * ssp->dss_secsize;
  267                 ic->ic_args[1].ia_ptr = sp;
  268                 bp->bio_done = dsiodone;
  269                 bp->bio_done_chain = ic;
  270                 if (!(bp->bio_cmd == BIO_READ)) {
  271                         /*
  272                          * XXX even disklabel(8) writes directly so we need
  273                          * to adjust writes.  Perhaps we should drop support
  274                          * for DIOCWLABEL (always write protect labels) and
  275                          * require the use of DIOCWDINFO.
  276                          *
  277                          * XXX probably need to copy the data to avoid even
  278                          * temporarily corrupting the in-core copy.
  279                          */
  280                         /* XXX need name here. */
  281                         msg = fixlabel((char *)NULL, sp,
  282                                        (struct disklabel *)
  283                                        (bp->bio_data + ic->ic_args[0].ia_long),
  284                                        TRUE);
  285                         if (msg != NULL) {
  286                                 printf("dscheck(%s): %s\n", 
  287                                     devtoname(bp->bio_dev), msg);
  288                                 bp->bio_error = EROFS;
  289                                 goto bad;
  290                         }
  291                 }
  292         }
  293         return (1);
  294 
  295 bad_bcount:
  296         printf(
  297         "dscheck(%s): bio_bcount %ld is not on a sector boundary (ssize %d)\n",
  298             devtoname(bp->bio_dev), bp->bio_bcount, ssp->dss_secsize);
  299         bp->bio_error = EINVAL;
  300         goto bad;
  301 
  302 bad_blkno:
  303         printf(
  304         "dscheck(%s): bio_blkno %ld is not on a sector boundary (ssize %d)\n",
  305             devtoname(bp->bio_dev), (long)blkno, ssp->dss_secsize);
  306         bp->bio_error = EINVAL;
  307         goto bad;
  308 
  309 bad:
  310         bp->bio_resid = bp->bio_bcount;
  311         bp->bio_flags |= BIO_ERROR;
  312         return (-1);
  313 }
  314 
  315 void
  316 dsclose(dev, mode, ssp)
  317         dev_t   dev;
  318         int     mode;
  319         struct diskslices *ssp;
  320 {
  321         u_char  mask;
  322         struct diskslice *sp;
  323 
  324         sp = &ssp->dss_slices[dkslice(dev)];
  325         mask = 1 << dkpart(dev);
  326         sp->ds_openmask &= ~mask;
  327 }
  328 
  329 void
  330 dsgone(sspp)
  331         struct diskslices **sspp;
  332 {
  333         int     slice;
  334         struct diskslice *sp;
  335         struct diskslices *ssp;
  336 
  337         for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
  338                 sp = &ssp->dss_slices[slice];
  339                 free_ds_label(ssp, slice);
  340         }
  341         free(ssp, M_DEVBUF);
  342         *sspp = NULL;
  343 }
  344 
  345 /*
  346  * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
  347  * is subject to the same restriction as dsopen().
  348  */
  349 int
  350 dsioctl(dev, cmd, data, flags, sspp)
  351         dev_t   dev;
  352         u_long  cmd;
  353         caddr_t data;
  354         int     flags;
  355         struct diskslices **sspp;
  356 {
  357         int     error;
  358         struct disklabel *lp;
  359         int     old_wlabel;
  360         u_char  openmask;
  361         int     part;
  362         int     slice;
  363         struct diskslice *sp;
  364         struct diskslices *ssp;
  365 
  366         slice = dkslice(dev);
  367         ssp = *sspp;
  368         sp = &ssp->dss_slices[slice];
  369         lp = sp->ds_label;
  370         switch (cmd) {
  371 
  372         case DIOCGDINFO:
  373                 if (lp == NULL)
  374                         return (EINVAL);
  375                 *(struct disklabel *)data = *lp;
  376                 return (0);
  377 
  378         case DIOCGMEDIASIZE:
  379                 if (lp == NULL)
  380                         *(off_t *)data = (off_t)sp->ds_size * ssp->dss_secsize;
  381                 else
  382                         *(off_t *)data =
  383                             (off_t)lp->d_partitions[dkpart(dev)].p_size *
  384                             lp->d_secsize;
  385                 return (0);
  386 
  387         case DIOCGSECTORSIZE:
  388                 *(u_int *)data = ssp->dss_secsize;
  389                 return (0);
  390 
  391         case DIOCGSLICEINFO:
  392                 bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
  393                                  (char *)ssp);
  394                 return (0);
  395 
  396         case DIOCSDINFO:
  397                 if (slice == WHOLE_DISK_SLICE)
  398                         return (ENODEV);
  399                 if (!(flags & FWRITE))
  400                         return (EBADF);
  401                 lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
  402                 if (sp->ds_label == NULL)
  403                         bzero(lp, sizeof *lp);
  404                 else
  405                         bcopy(sp->ds_label, lp, sizeof *lp);
  406                 if (sp->ds_label == NULL)
  407                         openmask = 0;
  408                 else {
  409                         openmask = sp->ds_openmask;
  410                         if (slice == COMPATIBILITY_SLICE)
  411                                 openmask |= ssp->dss_slices[
  412                                     ssp->dss_first_bsd_slice].ds_openmask;
  413                         else if (slice == ssp->dss_first_bsd_slice)
  414                                 openmask |= ssp->dss_slices[
  415                                     COMPATIBILITY_SLICE].ds_openmask;
  416                 }
  417                 error = setdisklabel(lp, (struct disklabel *)data,
  418                                      (u_long)openmask);
  419                 /* XXX why doesn't setdisklabel() check this? */
  420                 if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0)
  421                         error = EXDEV;
  422                 if (error == 0) {
  423                         if (lp->d_secperunit > sp->ds_size)
  424                                 error = ENOSPC;
  425                         for (part = 0; part < lp->d_npartitions; part++)
  426                                 if (lp->d_partitions[part].p_size > sp->ds_size)
  427                                         error = ENOSPC;
  428                 }
  429                 if (error != 0) {
  430                         free(lp, M_DEVBUF);
  431                         return (error);
  432                 }
  433                 free_ds_label(ssp, slice);
  434                 set_ds_label(ssp, slice, lp);
  435                 set_ds_labeldevs(dev, ssp);
  436                 return (0);
  437 
  438         case DIOCSYNCSLICEINFO:
  439                 if (slice != WHOLE_DISK_SLICE || dkpart(dev) != RAW_PART)
  440                         return (EINVAL);
  441                 if (!*(int *)data)
  442                         for (slice = 0; slice < ssp->dss_nslices; slice++) {
  443                                 openmask = ssp->dss_slices[slice].ds_openmask;
  444                                 if (openmask
  445                                     && (slice != WHOLE_DISK_SLICE
  446                                         || openmask & ~(1 << RAW_PART)))
  447                                         return (EBUSY);
  448                         }
  449 
  450                 /*
  451                  * Temporarily forget the current slices struct and read
  452                  * the current one.
  453                  * XXX should wait for current accesses on this disk to
  454                  * complete, then lock out future accesses and opens.
  455                  */
  456                 *sspp = NULL;
  457                 lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
  458                 *lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
  459                 error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, lp);
  460                 if (error != 0) {
  461                         free(lp, M_DEVBUF);
  462                         *sspp = ssp;
  463                         return (error);
  464                 }
  465 
  466                 /*
  467                  * Reopen everything.  This is a no-op except in the "force"
  468                  * case and when the raw bdev and cdev are both open.  Abort
  469                  * if anything fails.
  470                  */
  471                 for (slice = 0; slice < ssp->dss_nslices; slice++) {
  472                         for (openmask = ssp->dss_slices[slice].ds_openmask,
  473                              part = 0; openmask; openmask >>= 1, part++) {
  474                                 if (!(openmask & 1))
  475                                         continue;
  476                                 error = dsopen(dkmodslice(dkmodpart(dev, part),
  477                                                           slice),
  478                                                S_IFCHR, ssp->dss_oflags, sspp,
  479                                                lp);
  480                                 if (error != 0) {
  481                                         free(lp, M_DEVBUF);
  482                                         *sspp = ssp;
  483                                         return (EBUSY);
  484                                 }
  485                         }
  486                 }
  487 
  488                 free(lp, M_DEVBUF);
  489                 dsgone(&ssp);
  490                 return (0);
  491 
  492         case DIOCWDINFO:
  493                 error = dsioctl(dev, DIOCSDINFO, data, flags, &ssp);
  494                 if (error != 0)
  495                         return (error);
  496                 /*
  497                  * XXX this used to hack on dk_openpart to fake opening
  498                  * partition 0 in case that is used instead of dkpart(dev).
  499                  */
  500                 old_wlabel = sp->ds_wlabel;
  501                 set_ds_wlabel(ssp, slice, TRUE);
  502                 error = writedisklabel(dev, sp->ds_label);
  503                 /* XXX should invalidate in-core label if write failed. */
  504                 set_ds_wlabel(ssp, slice, old_wlabel);
  505                 return (error);
  506 
  507         case DIOCWLABEL:
  508 #ifndef __alpha__
  509                 if (slice == WHOLE_DISK_SLICE)
  510                         return (ENODEV);
  511 #endif
  512                 if (!(flags & FWRITE))
  513                         return (EBADF);
  514                 set_ds_wlabel(ssp, slice, *(int *)data != 0);
  515                 return (0);
  516 
  517         default:
  518                 return (ENOIOCTL);
  519         }
  520 }
  521 
  522 static void
  523 dsiodone(bp)
  524         struct bio *bp;
  525 {
  526         struct iodone_chain *ic;
  527         char *msg;
  528 
  529         ic = bp->bio_done_chain;
  530         bp->bio_done = ic->ic_prev_iodone;
  531         bp->bio_done_chain = ic->ic_prev_iodone_chain;
  532         if (!(bp->bio_cmd == BIO_READ)
  533             || (!(bp->bio_flags & BIO_ERROR) && bp->bio_error == 0)) {
  534                 msg = fixlabel((char *)NULL, ic->ic_args[1].ia_ptr,
  535                                (struct disklabel *)
  536                                (bp->bio_data + ic->ic_args[0].ia_long),
  537                                FALSE);
  538                 if (msg != NULL)
  539                         printf("%s\n", msg);
  540         }
  541         free(ic, M_DEVBUF);
  542         biodone(bp);
  543 }
  544 
  545 int
  546 dsisopen(ssp)
  547         struct diskslices *ssp;
  548 {
  549         int     slice;
  550 
  551         if (ssp == NULL)
  552                 return (0);
  553         for (slice = 0; slice < ssp->dss_nslices; slice++)
  554                 if (ssp->dss_slices[slice].ds_openmask)
  555                         return (1);
  556         return (0);
  557 }
  558 
  559 /*
  560  * Allocate a slices "struct" and initialize it to contain only an empty
  561  * compatibility slice (pointing to itself), a whole disk slice (covering
  562  * the disk as described by the label), and (nslices - BASE_SLICES) empty
  563  * slices beginning at BASE_SLICE.
  564  */
  565 struct diskslices *
  566 dsmakeslicestruct(nslices, lp)
  567         int nslices;
  568         struct disklabel *lp;
  569 {
  570         struct diskslice *sp;
  571         struct diskslices *ssp;
  572 
  573         ssp = malloc(offsetof(struct diskslices, dss_slices) +
  574                      nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
  575         ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
  576         ssp->dss_nslices = nslices;
  577         ssp->dss_oflags = 0;
  578         ssp->dss_secmult = lp->d_secsize / DEV_BSIZE;
  579         if (ssp->dss_secmult & (ssp->dss_secmult - 1))
  580                 ssp->dss_secshift = -1;
  581         else
  582                 ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
  583         ssp->dss_secsize = lp->d_secsize;
  584         sp = &ssp->dss_slices[0];
  585         bzero(sp, nslices * sizeof *sp);
  586         sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit;
  587         return (ssp);
  588 }
  589 
  590 char *
  591 dsname(dev, unit, slice, part, partname)
  592         dev_t   dev;
  593         int     unit;
  594         int     slice;
  595         int     part;
  596         char    *partname;
  597 {
  598         static char name[32];
  599         const char *dname;
  600 
  601         dname = devsw(dev)->d_name;
  602         if (strlen(dname) > 16)
  603                 dname = "nametoolong";
  604         snprintf(name, sizeof(name), "%s%d", dname, unit);
  605         partname[0] = '\0';
  606         if (slice != WHOLE_DISK_SLICE || part != RAW_PART) {
  607                 partname[0] = 'a' + part;
  608                 partname[1] = '\0';
  609                 if (slice != COMPATIBILITY_SLICE)
  610                         snprintf(name + strlen(name),
  611                             sizeof(name) - strlen(name), "s%d", slice - 1);
  612         }
  613         return (name);
  614 }
  615 
  616 /*
  617  * This should only be called when the unit is inactive and the strategy
  618  * routine should not allow it to become active unless we call it.  Our
  619  * strategy routine must be special to allow activity.
  620  */
  621 int
  622 dsopen(dev, mode, flags, sspp, lp)
  623         dev_t   dev;
  624         int     mode;
  625         u_int   flags;
  626         struct diskslices **sspp;
  627         struct disklabel *lp;
  628 {
  629         dev_t   dev1;
  630         int     error;
  631         struct disklabel *lp1;
  632         char    *msg;
  633         u_char  mask;
  634         int     part;
  635         char    partname[2];
  636         int     slice;
  637         char    *sname;
  638         struct diskslice *sp;
  639         struct diskslices *ssp;
  640         int     unit;
  641 
  642         dev->si_bsize_phys = lp->d_secsize;
  643 
  644         unit = dkunit(dev);
  645         if (lp->d_secsize % DEV_BSIZE) {
  646                 printf("%s: invalid sector size %lu\n", devtoname(dev),
  647                     (u_long)lp->d_secsize);
  648                 return (EINVAL);
  649         }
  650 
  651         /*
  652          * XXX reinitialize the slice table unless there is an open device
  653          * on the unit.  This should only be done if the media has changed.
  654          */
  655         ssp = *sspp;
  656         if (!dsisopen(ssp)) {
  657                 if (ssp != NULL)
  658                         dsgone(sspp);
  659                 /*
  660                  * Allocate a minimal slices "struct".  This will become
  661                  * the final slices "struct" if we don't want real slices
  662                  * or if we can't find any real slices.
  663                  */
  664                 *sspp = dsmakeslicestruct(BASE_SLICE, lp);
  665 
  666                 if (!(flags & DSO_ONESLICE)) {
  667                         TRACE(("dsinit\n"));
  668                         error = dsinit(dev, lp, sspp);
  669                         if (error != 0) {
  670                                 dsgone(sspp);
  671                                 return (error);
  672                         }
  673                 }
  674                 ssp = *sspp;
  675                 ssp->dss_oflags = flags;
  676 
  677                 /*
  678                  * If there are no real slices, then make the compatiblity
  679                  * slice cover the whole disk.
  680                  */
  681                 if (ssp->dss_nslices == BASE_SLICE)
  682                         ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
  683                                 = lp->d_secperunit;
  684 
  685                 /* Point the compatibility slice at the BSD slice, if any. */
  686                 for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
  687                         sp = &ssp->dss_slices[slice];
  688                         if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
  689                                 ssp->dss_first_bsd_slice = slice;
  690                                 ssp->dss_slices[COMPATIBILITY_SLICE].ds_offset
  691                                         = sp->ds_offset;
  692                                 ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
  693                                         = sp->ds_size;
  694                                 ssp->dss_slices[COMPATIBILITY_SLICE].ds_type
  695                                         = sp->ds_type;
  696                                 break;
  697                         }
  698                 }
  699 
  700                 ssp->dss_slices[WHOLE_DISK_SLICE].ds_label = clone_label(lp);
  701                 ssp->dss_slices[WHOLE_DISK_SLICE].ds_wlabel = TRUE;
  702         }
  703 
  704         /* Initialize secondary info for all slices.  */
  705         for (slice = 0; slice < ssp->dss_nslices; slice++) {
  706                 sp = &ssp->dss_slices[slice];
  707                 if (sp->ds_label != NULL
  708 #ifdef __alpha__
  709                     && slice != WHOLE_DISK_SLICE
  710 #endif
  711                     )
  712                         continue;
  713                 dev1 = dkmodslice(dkmodpart(dev, RAW_PART), slice);
  714 #if 0
  715                 sname = dsname(dev, unit, slice, RAW_PART, partname);
  716 #else
  717                 *partname='\0';
  718                 sname = dev1->si_name;
  719 #endif
  720                 /*
  721                  * XXX this should probably only be done for the need_init
  722                  * case, but there may be a problem with DIOCSYNCSLICEINFO.
  723                  */
  724                 set_ds_wlabel(ssp, slice, TRUE);        /* XXX invert */
  725                 lp1 = clone_label(lp);
  726                 TRACE(("readdisklabel\n"));
  727                 if (flags & DSO_NOLABELS)
  728                         msg = NULL;
  729                 else {
  730                         msg = readdisklabel(dev1, lp1);
  731 
  732                         /*
  733                          * readdisklabel() returns NULL for success, and an
  734                          * error string for failure.
  735                          *
  736                          * If there isn't a label on the disk, and if the
  737                          * DSO_COMPATLABEL is set, we want to use the
  738                          * faked-up label provided by the caller.
  739                          *
  740                          * So we set msg to NULL to indicate that there is
  741                          * no failure (since we have a faked-up label),
  742                          * free lp1, and then clone it again from lp.
  743                          * (In case readdisklabel() modified lp1.)
  744                          */
  745                         if (msg != NULL && (flags & DSO_COMPATLABEL)) {
  746                                 msg = NULL;
  747                                 free(lp1, M_DEVBUF);
  748                                 lp1 = clone_label(lp);
  749                         }
  750                 }
  751                 if (msg == NULL)
  752                         msg = fixlabel(sname, sp, lp1, FALSE);
  753                 if (msg == NULL && lp1->d_secsize != ssp->dss_secsize)
  754                         msg = "inconsistent sector size";
  755                 if (msg != NULL) {
  756                         if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
  757                                 log(LOG_WARNING, "%s: cannot find label (%s)\n",
  758                                     sname, msg);
  759                         free(lp1, M_DEVBUF);
  760                         continue;
  761                 }
  762                 if (lp1->d_flags & D_BADSECT) {
  763                         log(LOG_ERR, "%s: bad sector table not supported\n",
  764                             sname);
  765                         free(lp1, M_DEVBUF);
  766                         continue;
  767                 }
  768                 set_ds_label(ssp, slice, lp1);
  769                 set_ds_labeldevs(dev1, ssp);
  770                 set_ds_wlabel(ssp, slice, FALSE);
  771         }
  772 
  773         slice = dkslice(dev);
  774         if (slice >= ssp->dss_nslices)
  775                 return (ENXIO);
  776         sp = &ssp->dss_slices[slice];
  777         part = dkpart(dev);
  778         if (part != RAW_PART
  779             && (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions))
  780                 return (EINVAL);        /* XXX needs translation */
  781         mask = 1 << part;
  782         sp->ds_openmask |= mask;
  783         return (0);
  784 }
  785 
  786 int
  787 dssize(dev, sspp)
  788         dev_t   dev;
  789         struct diskslices **sspp;
  790 {
  791         struct disklabel *lp;
  792         int     part;
  793         int     slice;
  794         struct diskslices *ssp;
  795 
  796         slice = dkslice(dev);
  797         part = dkpart(dev);
  798         ssp = *sspp;
  799         if (ssp == NULL || slice >= ssp->dss_nslices
  800             || !(ssp->dss_slices[slice].ds_openmask & (1 << part))) {
  801                 if (devsw(dev)->d_open(dev, FREAD, S_IFCHR,
  802                     (struct thread *)NULL) != 0)
  803                         return (-1);
  804                 devsw(dev)->d_close(dev, FREAD, S_IFCHR, (struct thread *)NULL);
  805                 ssp = *sspp;
  806         }
  807         lp = ssp->dss_slices[slice].ds_label;
  808         if (lp == NULL)
  809                 return (-1);
  810         return ((int)lp->d_partitions[part].p_size);
  811 }
  812 
  813 static void
  814 free_ds_label(ssp, slice)
  815         struct diskslices *ssp;
  816         int     slice;
  817 {
  818         struct disklabel *lp;
  819         struct diskslice *sp;
  820 
  821         sp = &ssp->dss_slices[slice];
  822         lp = sp->ds_label;
  823         if (lp == NULL)
  824                 return;
  825         free(lp, M_DEVBUF);
  826         set_ds_label(ssp, slice, (struct disklabel *)NULL);
  827 }
  828 
  829 
  830 static char *
  831 fixlabel(sname, sp, lp, writeflag)
  832         char    *sname;
  833         struct diskslice *sp;
  834         struct disklabel *lp;
  835         int     writeflag;
  836 {
  837         u_long  end;
  838         u_long  offset;
  839         int     part;
  840         struct partition *pp;
  841         u_long  start;
  842         bool_t  warned;
  843 
  844         /* These errors "can't happen" so don't bother reporting details. */
  845         if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC)
  846                 return ("fixlabel: invalid magic");
  847         if (dkcksum(lp) != 0)
  848                 return ("fixlabel: invalid checksum");
  849 
  850         pp = &lp->d_partitions[RAW_PART];
  851         if (writeflag) {
  852                 start = 0;
  853                 offset = sp->ds_offset;
  854         } else {
  855                 start = sp->ds_offset;
  856                 offset = -sp->ds_offset;
  857         }
  858         if (pp->p_offset != start) {
  859                 if (sname != NULL) {
  860                         printf(
  861 "%s: rejecting BSD label: raw partition offset != slice offset\n",
  862                                sname);
  863                         slice_info(sname, sp);
  864                         partition_info(sname, RAW_PART, pp);
  865                 }
  866                 return ("fixlabel: raw partition offset != slice offset");
  867         }
  868         if (pp->p_size != sp->ds_size) {
  869                 if (sname != NULL) {
  870                         printf("%s: raw partition size != slice size\n", sname);
  871                         slice_info(sname, sp);
  872                         partition_info(sname, RAW_PART, pp);
  873                 }
  874                 if (pp->p_size > sp->ds_size) {
  875                         if (sname == NULL)
  876                                 return ("fixlabel: raw partition size > slice size");
  877                         printf("%s: truncating raw partition\n", sname);
  878                         pp->p_size = sp->ds_size;
  879                 }
  880         }
  881         end = start + sp->ds_size;
  882         if (start > end)
  883                 return ("fixlabel: slice wraps");
  884         if (lp->d_secpercyl <= 0)
  885                 return ("fixlabel: d_secpercyl <= 0");
  886         pp -= RAW_PART;
  887         warned = FALSE;
  888         for (part = 0; part < lp->d_npartitions; part++, pp++) {
  889                 if (pp->p_offset != 0 || pp->p_size != 0) {
  890                         if (pp->p_offset < start
  891                             || pp->p_offset + pp->p_size > end
  892                             || pp->p_offset + pp->p_size < pp->p_offset) {
  893                                 if (sname != NULL) {
  894                                         printf(
  895 "%s: rejecting partition in BSD label: it isn't entirely within the slice\n",
  896                                                sname);
  897                                         if (!warned) {
  898                                                 slice_info(sname, sp);
  899                                                 warned = TRUE;
  900                                         }
  901                                         partition_info(sname, part, pp);
  902                                 }
  903                                 /* XXX else silently discard junk. */
  904                                 bzero(pp, sizeof *pp);
  905                         } else
  906                                 pp->p_offset += offset;
  907                 }
  908         }
  909         lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
  910         lp->d_secperunit = sp->ds_size;
  911         lp->d_checksum = 0;
  912         lp->d_checksum = dkcksum(lp);
  913         return (NULL);
  914 }
  915 
  916 static void
  917 partition_info(sname, part, pp)
  918         char    *sname;
  919         int     part;
  920         struct partition *pp;
  921 {
  922         printf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part,
  923                (u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1),
  924                (u_long)pp->p_size);
  925 }
  926 
  927 static void
  928 slice_info(sname, sp)
  929         char    *sname;
  930         struct diskslice *sp;
  931 {
  932         printf("%s: start %lu, end %lu, size %lu\n", sname,
  933                sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size);
  934 }
  935 
  936 static void
  937 set_ds_label(ssp, slice, lp)
  938         struct diskslices *ssp;
  939         int     slice;
  940         struct disklabel *lp;
  941 {
  942         ssp->dss_slices[slice].ds_label = lp;
  943         if (slice == COMPATIBILITY_SLICE)
  944                 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_label = lp;
  945         else if (slice == ssp->dss_first_bsd_slice)
  946                 ssp->dss_slices[COMPATIBILITY_SLICE].ds_label = lp;
  947 }
  948 
  949 static void
  950 set_ds_labeldevs(dev, ssp)
  951         dev_t   dev;
  952         struct diskslices *ssp;
  953 {
  954 }
  955 
  956 
  957 static void
  958 set_ds_wlabel(ssp, slice, wlabel)
  959         struct diskslices *ssp;
  960         int     slice;
  961         int     wlabel;
  962 {
  963         ssp->dss_slices[slice].ds_wlabel = wlabel;
  964         if (slice == COMPATIBILITY_SLICE)
  965                 ssp->dss_slices[ssp->dss_first_bsd_slice].ds_wlabel = wlabel;
  966         else if (slice == ssp->dss_first_bsd_slice)
  967                 ssp->dss_slices[COMPATIBILITY_SLICE].ds_wlabel = wlabel;
  968 }

Cache object: ff753709c1b920d5fb0a0f6b1bd168a7


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