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

Cache object: c6bfe075129127bb7f9b2b4b62841b76


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