home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / ufs / ufs_disksubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-06  |  10.3 KB  |  359 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)ufs_disksubr.c    7.16 (Berkeley) 5/4/91
  34.  */
  35.  
  36. #include "param.h"
  37. #include "systm.h"
  38. #include "buf.h"
  39. #include "disklabel.h"
  40. #include "syslog.h"
  41.  
  42. /*
  43.  * Seek sort for disks.  We depend on the driver
  44.  * which calls us using b_resid as the current cylinder number.
  45.  *
  46.  * The argument dp structure holds a b_actf activity chain pointer
  47.  * on which we keep two queues, sorted in ascending cylinder order.
  48.  * The first queue holds those requests which are positioned after
  49.  * the current cylinder (in the first request); the second holds
  50.  * requests which came in after their cylinder number was passed.
  51.  * Thus we implement a one way scan, retracting after reaching the
  52.  * end of the drive to the first request on the second queue,
  53.  * at which time it becomes the first queue.
  54.  *
  55.  * A one-way scan is natural because of the way UNIX read-ahead
  56.  * blocks are allocated.
  57.  */
  58.  
  59. #define    b_cylin    b_resid
  60.  
  61. disksort(dp, bp)
  62.     register struct buf *dp, *bp;
  63. {
  64.     register struct buf *ap;
  65.  
  66.     /*
  67.      * If nothing on the activity queue, then
  68.      * we become the only thing.
  69.      */
  70.     ap = dp->b_actf;
  71.     if(ap == NULL) {
  72.         dp->b_actf = bp;
  73.         dp->b_actl = bp;
  74.         bp->av_forw = NULL;
  75.         return;
  76.     }
  77.     /*
  78.      * If we lie after the first (currently active)
  79.      * request, then we must locate the second request list
  80.      * and add ourselves to it.
  81.      */
  82.     if (bp->b_cylin < ap->b_cylin) {
  83.         while (ap->av_forw) {
  84.             /*
  85.              * Check for an ``inversion'' in the
  86.              * normally ascending cylinder numbers,
  87.              * indicating the start of the second request list.
  88.              */
  89.             if (ap->av_forw->b_cylin < ap->b_cylin) {
  90.                 /*
  91.                  * Search the second request list
  92.                  * for the first request at a larger
  93.                  * cylinder number.  We go before that;
  94.                  * if there is no such request, we go at end.
  95.                  */
  96.                 do {
  97.                     if (bp->b_cylin < ap->av_forw->b_cylin)
  98.                         goto insert;
  99.                     if (bp->b_cylin == ap->av_forw->b_cylin &&
  100.                         bp->b_blkno < ap->av_forw->b_blkno)
  101.                         goto insert;
  102.                     ap = ap->av_forw;
  103.                 } while (ap->av_forw);
  104.                 goto insert;        /* after last */
  105.             }
  106.             ap = ap->av_forw;
  107.         }
  108.         /*
  109.          * No inversions... we will go after the last, and
  110.          * be the first request in the second request list.
  111.          */
  112.         goto insert;
  113.     }
  114.     /*
  115.      * Request is at/after the current request...
  116.      * sort in the first request list.
  117.      */
  118.     while (ap->av_forw) {
  119.         /*
  120.          * We want to go after the current request
  121.          * if there is an inversion after it (i.e. it is
  122.          * the end of the first request list), or if
  123.          * the next request is a larger cylinder than our request.
  124.          */
  125.         if (ap->av_forw->b_cylin < ap->b_cylin ||
  126.             bp->b_cylin < ap->av_forw->b_cylin ||
  127.             (bp->b_cylin == ap->av_forw->b_cylin &&
  128.             bp->b_blkno < ap->av_forw->b_blkno))
  129.             goto insert;
  130.         ap = ap->av_forw;
  131.     }
  132.     /*
  133.      * Neither a second list nor a larger
  134.      * request... we go at the end of the first list,
  135.      * which is the same as the end of the whole schebang.
  136.      */
  137. insert:
  138.     bp->av_forw = ap->av_forw;
  139.     ap->av_forw = bp;
  140.     if (ap == dp->b_actl)
  141.         dp->b_actl = bp;
  142. }
  143.  
  144. /*
  145.  * Attempt to read a disk label from a device
  146.  * using the indicated stategy routine.
  147.  * The label must be partly set up before this:
  148.  * secpercyl and anything required in the strategy routine
  149.  * (e.g., sector size) must be filled in before calling us.
  150.  * Returns null on success and an error string on failure.
  151.  */
  152. char *
  153. readdisklabel(dev, strat, lp)
  154.     dev_t dev;
  155.     int (*strat)();
  156.     register struct disklabel *lp;
  157. {
  158.     register struct buf *bp;
  159.     struct disklabel *dlp;
  160.     char *msg = NULL;
  161.  
  162.     if (lp->d_secperunit == 0)
  163.         lp->d_secperunit = 0x1fffffff;
  164.     lp->d_npartitions = 1;
  165.     if (lp->d_partitions[0].p_size == 0)
  166.         lp->d_partitions[0].p_size = 0x1fffffff;
  167.     lp->d_partitions[0].p_offset = 0;
  168.  
  169.     bp = geteblk((int)lp->d_secsize);
  170.     bp->b_dev = dev;
  171.     bp->b_blkno = LABELSECTOR;
  172.     bp->b_bcount = lp->d_secsize;
  173.     bp->b_flags = B_BUSY | B_READ;
  174.     bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
  175.     (*strat)(bp);
  176.     if (biowait(bp)) {
  177.         msg = "I/O error";
  178.     } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
  179.         dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
  180.         dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
  181.         if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
  182.             if (msg == NULL)
  183.                 msg = "no disk label";
  184.         } else if (dlp->d_npartitions > MAXPARTITIONS ||
  185.                dkcksum(dlp) != 0)
  186.             msg = "disk label corrupted";
  187.         else {
  188.             *lp = *dlp;
  189.             msg = NULL;
  190.             break;
  191.         }
  192.     }
  193.     bp->b_flags = B_INVAL | B_AGE;
  194.     brelse(bp);
  195.     return (msg);
  196. }
  197.  
  198. /*
  199.  * Check new disk label for sensibility
  200.  * before setting it.
  201.  */
  202. setdisklabel(olp, nlp, openmask)
  203.     register struct disklabel *olp, *nlp;
  204.     u_long openmask;
  205. {
  206.     register i;
  207.     register struct partition *opp, *npp;
  208.  
  209.     if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
  210.         dkcksum(nlp) != 0)
  211.         return (EINVAL);
  212.     while ((i = ffs((long)openmask)) != 0) {
  213.         i--;
  214.         openmask &= ~(1 << i);
  215.         if (nlp->d_npartitions <= i)
  216.             return (EBUSY);
  217.         opp = &olp->d_partitions[i];
  218.         npp = &nlp->d_partitions[i];
  219.         if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
  220.             return (EBUSY);
  221.         /*
  222.          * Copy internally-set partition information
  223.          * if new label doesn't include it.        XXX
  224.          */
  225.         if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
  226.             npp->p_fstype = opp->p_fstype;
  227.             npp->p_fsize = opp->p_fsize;
  228.             npp->p_frag = opp->p_frag;
  229.             npp->p_cpg = opp->p_cpg;
  230.         }
  231.     }
  232.      nlp->d_checksum = 0;
  233.      nlp->d_checksum = dkcksum(nlp);
  234.     *olp = *nlp;
  235.     return (0);
  236. }
  237.  
  238. /* encoding of disk minor numbers, should be elsewhere... */
  239. #define dkunit(dev)        (minor(dev) >> 3)
  240. #define dkpart(dev)        (minor(dev) & 07)
  241. #define dkminor(unit, part)    (((unit) << 3) | (part))
  242.  
  243. /*
  244.  * Write disk label back to device after modification.
  245.  */
  246. writedisklabel(dev, strat, lp)
  247.     dev_t dev;
  248.     int (*strat)();
  249.     register struct disklabel *lp;
  250. {
  251.     struct buf *bp;
  252.     struct disklabel *dlp;
  253.     int labelpart;
  254.     int error = 0;
  255.  
  256.     labelpart = dkpart(dev);
  257.     if (lp->d_partitions[labelpart].p_offset != 0) {
  258.         if (lp->d_partitions[0].p_offset != 0)
  259.             return (EXDEV);            /* not quite right */
  260.         labelpart = 0;
  261.     }
  262.     bp = geteblk((int)lp->d_secsize);
  263.     bp->b_dev = makedev(major(dev), dkminor(dkunit(dev), labelpart));
  264.     bp->b_blkno = LABELSECTOR;
  265.     bp->b_bcount = lp->d_secsize;
  266.     bp->b_flags = B_READ;
  267.     (*strat)(bp);
  268.     if (error = biowait(bp))
  269.         goto done;
  270.     for (dlp = (struct disklabel *)bp->b_un.b_addr;
  271.         dlp <= (struct disklabel *)
  272.           (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
  273.         dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
  274.         if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
  275.             dkcksum(dlp) == 0) {
  276.             *dlp = *lp;
  277.             bp->b_flags = B_WRITE;
  278.             (*strat)(bp);
  279.             error = biowait(bp);
  280.             goto done;
  281.         }
  282.     }
  283.     error = ESRCH;
  284. done:
  285.     brelse(bp);
  286.     return (error);
  287. }
  288.  
  289. /*
  290.  * Compute checksum for disk label.
  291.  */
  292. dkcksum(lp)
  293.     register struct disklabel *lp;
  294. {
  295.     register u_short *start, *end;
  296.     register u_short sum = 0;
  297.  
  298.     start = (u_short *)lp;
  299.     end = (u_short *)&lp->d_partitions[lp->d_npartitions];
  300.     while (start < end)
  301.         sum ^= *start++;
  302.     return (sum);
  303. }
  304.  
  305. /*
  306.  * Disk error is the preface to plaintive error messages
  307.  * about failing disk transfers.  It prints messages of the form
  308.  
  309. hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
  310.  
  311.  * if the offset of the error in the transfer and a disk label
  312.  * are both available.  blkdone should be -1 if the position of the error
  313.  * is unknown; the disklabel pointer may be null from drivers that have not
  314.  * been converted to use them.  The message is printed with printf
  315.  * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
  316.  * The message should be completed (with at least a newline) with printf
  317.  * or addlog, respectively.  There is no trailing space.
  318.  */
  319. diskerr(bp, dname, what, pri, blkdone, lp)
  320.     register struct buf *bp;
  321.     char *dname, *what;
  322.     int pri, blkdone;
  323.     register struct disklabel *lp;
  324. {
  325.     int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev);
  326.     register void (*pr) __P((const char *, ...));
  327.     char partname = 'a' + part;
  328.     int sn;
  329.  
  330.     if (pri != LOG_PRINTF) {
  331.         log(pri, "");
  332.         pr = addlog;
  333.     } else
  334.         pr = printf;
  335.     (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what,
  336.         bp->b_flags & B_READ ? "read" : "writ");
  337.     sn = bp->b_blkno;
  338.     if (bp->b_bcount <= DEV_BSIZE)
  339.         (*pr)("%d", sn);
  340.     else {
  341.         if (blkdone >= 0) {
  342.             sn += blkdone;
  343.             (*pr)("%d of ", sn);
  344.         }
  345.         (*pr)("%d-%d", bp->b_blkno,
  346.             bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE);
  347.     }
  348.     if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
  349. #ifdef tahoe
  350.         sn *= DEV_BSIZE / lp->d_secsize;        /* XXX */
  351. #endif
  352.         sn += lp->d_partitions[part].p_offset;
  353.         (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn,
  354.             sn / lp->d_secpercyl);
  355.         sn %= lp->d_secpercyl;
  356.         (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors);
  357.     }
  358. }
  359.