From a97b572a5ea4d6e53b701c2083243799493c9229 Mon Sep 17 00:00:00 2001 From: "William F. Jolitz" Date: Tue, 14 Jul 1992 16:54:55 -0800 Subject: [PATCH] 386BSD 0.1 development Work on file usr/src/sys.386bsd/ufs/ufs_disksubr.c Co-Authored-By: Lynne Greer Jolitz Synthesized-from: 386BSD-0.1 --- usr/src/sys.386bsd/ufs/ufs_disksubr.c | 591 ++++++++++++++++++++++++++ 1 file changed, 591 insertions(+) create mode 100644 usr/src/sys.386bsd/ufs/ufs_disksubr.c diff --git a/usr/src/sys.386bsd/ufs/ufs_disksubr.c b/usr/src/sys.386bsd/ufs/ufs_disksubr.c new file mode 100644 index 0000000000..2ee669e215 --- /dev/null +++ b/usr/src/sys.386bsd/ufs/ufs_disksubr.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 + */ + +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "dkbad.h" +#include "disklabel.h" +#include "syslog.h" + +/* + * Seek sort for disks. We depend on the driver + * which calls us using b_resid as the current cylinder number. + * + * The argument dp structure holds a b_actf activity chain pointer + * on which we keep two queues, sorted in ascending cylinder order. + * The first queue holds those requests which are positioned after + * the current cylinder (in the first request); the second holds + * requests which came in after their cylinder number was passed. + * Thus we implement a one way scan, retracting after reaching the + * end of the drive to the first request on the second queue, + * at which time it becomes the first queue. + * + * A one-way scan is natural because of the way UNIX read-ahead + * blocks are allocated. + */ + +#define b_cylin b_resid + +void +disksort(dp, bp) + register struct buf *dp, *bp; +{ + register struct buf *ap; + + /* + * If nothing on the activity queue, then + * we become the only thing. + */ + ap = dp->b_actf; + if(ap == NULL) { + dp->b_actf = bp; + dp->b_actl = bp; + bp->av_forw = NULL; + return; + } + /* + * If we lie after the first (currently active) + * request, then we must locate the second request list + * and add ourselves to it. + */ + if (bp->b_cylin < ap->b_cylin) { + while (ap->av_forw) { + /* + * Check for an ``inversion'' in the + * normally ascending cylinder numbers, + * indicating the start of the second request list. + */ + if (ap->av_forw->b_cylin < ap->b_cylin) { + /* + * Search the second request list + * for the first request at a larger + * cylinder number. We go before that; + * if there is no such request, we go at end. + */ + do { + if (bp->b_cylin < ap->av_forw->b_cylin) + goto insert; + if (bp->b_cylin == ap->av_forw->b_cylin && + bp->b_blkno < ap->av_forw->b_blkno) + goto insert; + ap = ap->av_forw; + } while (ap->av_forw); + goto insert; /* after last */ + } + ap = ap->av_forw; + } + /* + * No inversions... we will go after the last, and + * be the first request in the second request list. + */ + goto insert; + } + /* + * Request is at/after the current request... + * sort in the first request list. + */ + while (ap->av_forw) { + /* + * We want to go after the current request + * if there is an inversion after it (i.e. it is + * the end of the first request list), or if + * the next request is a larger cylinder than our request. + */ + if (ap->av_forw->b_cylin < ap->b_cylin || + bp->b_cylin < ap->av_forw->b_cylin || + (bp->b_cylin == ap->av_forw->b_cylin && + bp->b_blkno < ap->av_forw->b_blkno)) + goto insert; + ap = ap->av_forw; + } + /* + * Neither a second list nor a larger + * request... we go at the end of the first list, + * which is the same as the end of the whole schebang. + */ +insert: + bp->av_forw = ap->av_forw; + ap->av_forw = bp; + if (ap == dp->b_actl) + dp->b_actl = bp; +} + +/* encoding of disk minor numbers, should be elsewhere... */ +#define dkunit(dev) (minor(dev) >> 3) +#define dkpart(dev) (minor(dev) & 7) +#define dkminor(unit, part) (((unit) << 3) | (part)) + +/* + * Attempt to read a disk label from a device + * using the indicated stategy routine. + * The label must be partly set up before this: + * secpercyl, secsize and anything required for a block i/o read + * operation in the driver's strategy/start routines + * must be filled in before calling us. + * + * If dos partition table requested, attempt to load it and + * find disklabel inside a DOS partition. Also, if bad block + * table needed, attempt to extract it as well. Return buffer + * for use in signalling errors if requested. + * + * Returns null on success and an error string on failure. + */ +char * +readdisklabel(dev, strat, lp, dp, bdp, bpp) + dev_t dev; + int (*strat)(); + register struct disklabel *lp; + struct dos_partition *dp; + struct dkbad *bdp; + struct buf **bpp; +{ + register struct buf *bp; + struct disklabel *dlp; + char *msg = NULL; + int cyl, dospartoff, i; + + /* minimal requirements for archtypal disk label */ + if (lp->d_secperunit == 0) + lp->d_secperunit = 0x1fffffff; + lp->d_npartitions = 1; + if (lp->d_partitions[0].p_size == 0) + lp->d_partitions[0].p_size = 0x1fffffff; + lp->d_partitions[0].p_offset = 0; + + /* obtain buffer to probe drive with */ + bp = geteblk((int)lp->d_secsize); + + /* request no partition relocation by driver on I/O operations */ + bp->b_dev = makedev(major(dev), dkminor((dkunit(dev)), 3)); + + /* do dos partitions in the process of getting disklabel? */ + dospartoff = 0; + cyl = LABELSECTOR / lp->d_secpercyl; + if (dp) { + struct dos_partition *ap; + + /* read master boot record */ + bp->b_blkno = DOSBBSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_cylin = DOSBBSECTOR / lp->d_secpercyl; + (*strat)(bp); + + /* if successful, wander through dos partition table */ + if (biowait(bp)) { + msg = "dos partition I/O error"; + goto done; + } else { + /* XXX how do we check veracity/bounds of this? */ + bcopy(bp->b_un.b_addr + DOSPARTOFF, dp, + NDOSPART * sizeof(*dp)); + for (i = 0; i < NDOSPART; i++, dp++) + /* is this ours? */ + if (dp->dp_size && + dp->dp_typ == DOSPTYP_386BSD + && dospartoff == 0) { + + /* need sector address for SCSI/IDE, + cylinder for ESDI/ST506/RLL */ + dospartoff = dp->dp_start; + cyl = DPCYL(dp->dp_scyl, dp->dp_ssect); + + /* update disklabel with details */ + lp->d_partitions[0].p_size = + dp->dp_size; + lp->d_partitions[0].p_offset = + dp->dp_start; + lp->d_ntracks = dp->dp_ehd + 1; + lp->d_nsectors = DPSECT(dp->dp_esect); + lp->d_subtype |= (lp->d_subtype & 3) + + i | DSTYPE_INDOSPART; + lp->d_secpercyl = lp->d_ntracks * + lp->d_nsectors; + } + } + + } + + /* next, dig out disk label */ + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_cylin = cyl; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + + /* if successful, locate disk label within block and validate */ + if (biowait(bp)) { + msg = "disk label I/O error"; + goto done; + } else for (dlp = (struct disklabel *)bp->b_un.b_addr; + dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp)); + dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { + if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { + if (msg == NULL) + msg = "no disk label"; + } else if (dlp->d_npartitions > MAXPARTITIONS || + dkcksum(dlp) != 0) + msg = "disk label corrupted"; + else { + *lp = *dlp; + msg = NULL; + break; + } + } + + if (msg) + goto done; + + /* obtain bad sector table if requested and present */ + if (bdp && (lp->d_flags & D_BADSECT)) { + struct dkbad *db; + + i = 0; + do { + /* read a bad sector table */ + bp->b_flags = B_BUSY | B_READ; + bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i; + if (lp->d_secsize > DEV_BSIZE) + bp->b_blkno *= lp->d_secsize / DEV_BSIZE; + else + bp->b_blkno /= DEV_BSIZE / lp->d_secsize; + bp->b_bcount = lp->d_secsize; + bp->b_cylin = lp->d_ncylinders - 1; + (*strat)(bp); + + /* if successful, validate, otherwise try another */ + if (biowait(bp)) { + msg = "bad sector table I/O error"; + } else { + db = (struct dkbad *)(bp->b_un.b_addr); +#define DKBAD_MAGIC 0x4321 + if (db->bt_mbz == 0 + && db->bt_flag == DKBAD_MAGIC) { + msg = NULL; + *bdp = *db; + break; + } else + msg = "bad sector table corrupted"; + } + } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 && + i < lp->d_nsectors); + } + +done: + bp->b_flags = B_INVAL | B_AGE | B_READ; +#ifndef old + /* if desired, pass back allocated block so caller can use */ + if (bpp) + *bpp = bp; + else +#endif + brelse(bp); + return (msg); +} + +/* + * Check new disk label for sensibility + * before setting it. + */ +setdisklabel(olp, nlp, openmask, dp) + register struct disklabel *olp, *nlp; + u_long openmask; + struct dos_partition *dp; +{ + register i; + register struct partition *opp, *npp; + + /* sanity clause */ + if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 + || (nlp->d_secsize % DEV_BSIZE) != 0) + return(EINVAL); + + /* special case to allow disklabel to be invalidated */ + if (nlp->d_magic == 0xffffffff) { + *olp = *nlp; + return (0); + } + + if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || + dkcksum(nlp) != 0) + return (EINVAL); + + /* XXX missing check if other dos partitions will be overwritten */ + + while ((i = ffs((long)openmask)) != 0) { + i--; + openmask &= ~(1 << i); + if (nlp->d_npartitions <= i) + return (EBUSY); + opp = &olp->d_partitions[i]; + npp = &nlp->d_partitions[i]; + if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) + return (EBUSY); + /* + * Copy internally-set partition information + * if new label doesn't include it. XXX + */ + if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { + npp->p_fstype = opp->p_fstype; + npp->p_fsize = opp->p_fsize; + npp->p_frag = opp->p_frag; + npp->p_cpg = opp->p_cpg; + } + } + nlp->d_checksum = 0; + nlp->d_checksum = dkcksum(nlp); + *olp = *nlp; + return (0); +} + + +/* + * Write disk label back to device after modification. + */ +writedisklabel(dev, strat, lp, dp) + dev_t dev; + int (*strat)(); + register struct disklabel *lp; + struct dos_partition *dp; +{ + struct buf *bp; + struct disklabel *dlp; + int labelpart, error = 0, dospartoff, cyl, i; + + labelpart = dkpart(dev); +#ifdef nope + if (lp->d_partitions[labelpart].p_offset != 0) { + if (lp->d_partitions[0].p_offset != 0) + return (EXDEV); /* not quite right */ + labelpart = 0; + } +#else + labelpart = 3; +#endif + + bp = geteblk((int)lp->d_secsize); + /* request no partition relocation by driver on I/O operations */ + bp->b_dev = makedev(major(dev), dkminor((dkunit(dev)), 3)); + + /* do dos partitions in the process of getting disklabel? */ + dospartoff = 0; + cyl = LABELSECTOR / lp->d_secpercyl; + if (dp) { + bp->b_blkno = DOSBBSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_cylin = DOSBBSECTOR / lp->d_secpercyl; + (*strat)(bp); + if ((error = biowait(bp)) == 0) { + bcopy(bp->b_un.b_addr + DOSPARTOFF, dp, + NDOSPART * sizeof(*dp)); + for (i = 0; i < NDOSPART; i++, dp++) + if(dp->dp_size && dp->dp_typ == DOSPTYP_386BSD + && dospartoff == 0) { + /* need sector address for SCSI/IDE, + cylinder for ESDI/ST506/RLL */ + dospartoff = dp->dp_start; + cyl = dp->dp_scyl | + ((dp->dp_ssect & 0xc0) << 2); + } + } + + } + +#ifdef maybe + /* disklabel in appropriate location? */ + if (lp->d_partitions[0].p_offset != 0 + && lp->d_partitions[0].p_offset != dospartoff) { + error = EXDEV; + goto done; + } +#endif + + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_cylin = cyl; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_READ; + (*strat)(bp); + if (error = biowait(bp)) + goto done; + for (dlp = (struct disklabel *)bp->b_un.b_addr; + dlp <= (struct disklabel *) + (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp)); + dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { + if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && + dkcksum(dlp) == 0) { + *dlp = *lp; + bp->b_flags = B_WRITE; + (*strat)(bp); + error = biowait(bp); + goto done; + } + } + error = ESRCH; +done: + brelse(bp); + return (error); +} + +/* + * Compute checksum for disk label. + */ +dkcksum(lp) + register struct disklabel *lp; +{ + register u_short *start, *end; + register u_short sum = 0; + + start = (u_short *)lp; + end = (u_short *)&lp->d_partitions[lp->d_npartitions]; + while (start < end) + sum ^= *start++; + return (sum); +} + +/* + * Determine the size of the transfer, and make sure it is + * within the boundaries of the partition. Adjust transfer + * if needed, and signal errors or early completion. + */ +int +bounds_check_with_label(struct buf *bp, struct disklabel *lp, int wlabel) +{ + struct partition *p = lp->d_partitions + dkpart(bp->b_dev); + int labelsect = lp->d_partitions[0].p_offset; + int maxsz = p->p_size, + sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; + + /* overwriting disk label ? */ + /* XXX should also protect bootstrap in first 8K */ + if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect && +#if LABELSECTOR != 0 + bp->b_blkno + p->p_offset + sz > LABELSECTOR + labelsect && +#endif + (bp->b_flags & B_READ) == 0 && wlabel == 0) { + bp->b_error = EROFS; + goto bad; + } + +#if defined(DOSBBSECTOR) && defined(notyet) + /* overwriting master boot record? */ + if (bp->b_blkno + p->p_offset <= DOSBBSECTOR && + (bp->b_flags & B_READ) == 0 && wlabel == 0) { + bp->b_error = EROFS; + goto bad; + } +#endif + + /* beyond partition? */ + if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { + /* if exactly at end of disk, return an EOF */ + if (bp->b_blkno == maxsz) { + bp->b_resid = bp->b_bcount; + return(0); + } + /* or truncate if part of it fits */ + sz = maxsz - bp->b_blkno; + if (sz <= 0) { + bp->b_error = EINVAL; + goto bad; + } + bp->b_bcount = sz << DEV_BSHIFT; + } + + /* calculate cylinder for disksort to order transfers with */ + bp->b_cylin = (bp->b_blkno + p->p_offset) / lp->d_secpercyl; + return(1); + +bad: + bp->b_flags |= B_ERROR; + return(-1); +} + +/* + * Disk error is the preface to plaintive error messages + * about failing disk transfers. It prints messages of the form + +hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) + + * if the offset of the error in the transfer and a disk label + * are both available. blkdone should be -1 if the position of the error + * is unknown; the disklabel pointer may be null from drivers that have not + * been converted to use them. The message is printed with printf + * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. + * The message should be completed (with at least a newline) with printf + * or addlog, respectively. There is no trailing space. + */ +void +diskerr(bp, dname, what, pri, blkdone, lp) + register struct buf *bp; + char *dname, *what; + int pri, blkdone; + register struct disklabel *lp; +{ + int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev); + register void (*pr) __P((const char *, ...)); + char partname = 'a' + part; + int sn; + + if (pri != LOG_PRINTF) { + log(pri, ""); + pr = addlog; + } else + pr = printf; + (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what, + bp->b_flags & B_READ ? "read" : "writ"); + sn = bp->b_blkno; + if (bp->b_bcount <= DEV_BSIZE) + (*pr)("%d", sn); + else { + if (blkdone >= 0) { + sn += blkdone; + (*pr)("%d of ", sn); + } + (*pr)("%d-%d", bp->b_blkno, + bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE); + } + if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { +#ifdef tahoe + sn *= DEV_BSIZE / lp->d_secsize; /* XXX */ +#endif + sn += lp->d_partitions[part].p_offset; + (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn, + sn / lp->d_secpercyl); + sn %= lp->d_secpercyl; + (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors); + } +} -- 2.20.1