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

Cache object: 57d9665092be9d60d8536eeddf4d299e


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