|
|
1.1 root 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"
1.1.1.2 ! root 39: #include "dkbad.h"
1.1 root 40: #include "disklabel.h"
41: #include "syslog.h"
42:
43: /*
44: * Seek sort for disks. We depend on the driver
45: * which calls us using b_resid as the current cylinder number.
46: *
47: * The argument dp structure holds a b_actf activity chain pointer
48: * on which we keep two queues, sorted in ascending cylinder order.
49: * The first queue holds those requests which are positioned after
50: * the current cylinder (in the first request); the second holds
51: * requests which came in after their cylinder number was passed.
52: * Thus we implement a one way scan, retracting after reaching the
53: * end of the drive to the first request on the second queue,
54: * at which time it becomes the first queue.
55: *
56: * A one-way scan is natural because of the way UNIX read-ahead
57: * blocks are allocated.
58: */
59:
60: #define b_cylin b_resid
61:
1.1.1.2 ! root 62: void
1.1 root 63: disksort(dp, bp)
64: register struct buf *dp, *bp;
65: {
66: register struct buf *ap;
67:
68: /*
69: * If nothing on the activity queue, then
70: * we become the only thing.
71: */
72: ap = dp->b_actf;
73: if(ap == NULL) {
74: dp->b_actf = bp;
75: dp->b_actl = bp;
76: bp->av_forw = NULL;
77: return;
78: }
79: /*
80: * If we lie after the first (currently active)
81: * request, then we must locate the second request list
82: * and add ourselves to it.
83: */
84: if (bp->b_cylin < ap->b_cylin) {
85: while (ap->av_forw) {
86: /*
87: * Check for an ``inversion'' in the
88: * normally ascending cylinder numbers,
89: * indicating the start of the second request list.
90: */
91: if (ap->av_forw->b_cylin < ap->b_cylin) {
92: /*
93: * Search the second request list
94: * for the first request at a larger
95: * cylinder number. We go before that;
96: * if there is no such request, we go at end.
97: */
98: do {
99: if (bp->b_cylin < ap->av_forw->b_cylin)
100: goto insert;
101: if (bp->b_cylin == ap->av_forw->b_cylin &&
102: bp->b_blkno < ap->av_forw->b_blkno)
103: goto insert;
104: ap = ap->av_forw;
105: } while (ap->av_forw);
106: goto insert; /* after last */
107: }
108: ap = ap->av_forw;
109: }
110: /*
111: * No inversions... we will go after the last, and
112: * be the first request in the second request list.
113: */
114: goto insert;
115: }
116: /*
117: * Request is at/after the current request...
118: * sort in the first request list.
119: */
120: while (ap->av_forw) {
121: /*
122: * We want to go after the current request
123: * if there is an inversion after it (i.e. it is
124: * the end of the first request list), or if
125: * the next request is a larger cylinder than our request.
126: */
127: if (ap->av_forw->b_cylin < ap->b_cylin ||
128: bp->b_cylin < ap->av_forw->b_cylin ||
129: (bp->b_cylin == ap->av_forw->b_cylin &&
130: bp->b_blkno < ap->av_forw->b_blkno))
131: goto insert;
132: ap = ap->av_forw;
133: }
134: /*
135: * Neither a second list nor a larger
136: * request... we go at the end of the first list,
137: * which is the same as the end of the whole schebang.
138: */
139: insert:
140: bp->av_forw = ap->av_forw;
141: ap->av_forw = bp;
142: if (ap == dp->b_actl)
143: dp->b_actl = bp;
144: }
145:
1.1.1.2 ! root 146: /* encoding of disk minor numbers, should be elsewhere... */
! 147: #define dkunit(dev) (minor(dev) >> 3)
! 148: #define dkpart(dev) (minor(dev) & 7)
! 149: #define dkminor(unit, part) (((unit) << 3) | (part))
! 150:
1.1 root 151: /*
152: * Attempt to read a disk label from a device
153: * using the indicated stategy routine.
154: * The label must be partly set up before this:
1.1.1.2 ! root 155: * secpercyl, secsize and anything required for a block i/o read
! 156: * operation in the driver's strategy/start routines
! 157: * must be filled in before calling us.
! 158: *
! 159: * If dos partition table requested, attempt to load it and
! 160: * find disklabel inside a DOS partition. Also, if bad block
! 161: * table needed, attempt to extract it as well. Return buffer
! 162: * for use in signalling errors if requested.
! 163: *
1.1 root 164: * Returns null on success and an error string on failure.
165: */
166: char *
1.1.1.2 ! root 167: readdisklabel(dev, strat, lp, dp, bdp, bpp)
1.1 root 168: dev_t dev;
169: int (*strat)();
170: register struct disklabel *lp;
1.1.1.2 ! root 171: struct dos_partition *dp;
! 172: struct dkbad *bdp;
! 173: struct buf **bpp;
1.1 root 174: {
175: register struct buf *bp;
176: struct disklabel *dlp;
177: char *msg = NULL;
1.1.1.2 ! root 178: int cyl, dospartoff, i;
1.1 root 179:
1.1.1.2 ! root 180: /* minimal requirements for archtypal disk label */
1.1 root 181: if (lp->d_secperunit == 0)
182: lp->d_secperunit = 0x1fffffff;
183: lp->d_npartitions = 1;
184: if (lp->d_partitions[0].p_size == 0)
185: lp->d_partitions[0].p_size = 0x1fffffff;
186: lp->d_partitions[0].p_offset = 0;
187:
1.1.1.2 ! root 188: /* obtain buffer to probe drive with */
1.1 root 189: bp = geteblk((int)lp->d_secsize);
1.1.1.2 ! root 190:
! 191: /* request no partition relocation by driver on I/O operations */
! 192: bp->b_dev = makedev(major(dev), dkminor((dkunit(dev)), 3));
! 193:
! 194: /* do dos partitions in the process of getting disklabel? */
! 195: dospartoff = 0;
! 196: cyl = LABELSECTOR / lp->d_secpercyl;
! 197: if (dp) {
! 198: struct dos_partition *ap;
! 199:
! 200: /* read master boot record */
! 201: bp->b_blkno = DOSBBSECTOR;
! 202: bp->b_bcount = lp->d_secsize;
! 203: bp->b_flags = B_BUSY | B_READ;
! 204: bp->b_cylin = DOSBBSECTOR / lp->d_secpercyl;
! 205: (*strat)(bp);
! 206:
! 207: /* if successful, wander through dos partition table */
! 208: if (biowait(bp)) {
! 209: msg = "dos partition I/O error";
! 210: goto done;
! 211: } else {
! 212: /* XXX how do we check veracity/bounds of this? */
! 213: bcopy(bp->b_un.b_addr + DOSPARTOFF, dp,
! 214: NDOSPART * sizeof(*dp));
! 215: for (i = 0; i < NDOSPART; i++, dp++)
! 216: /* is this ours? */
! 217: if (dp->dp_size &&
! 218: dp->dp_typ == DOSPTYP_386BSD
! 219: && dospartoff == 0) {
! 220:
! 221: /* need sector address for SCSI/IDE,
! 222: cylinder for ESDI/ST506/RLL */
! 223: dospartoff = dp->dp_start;
! 224: cyl = DPCYL(dp->dp_scyl, dp->dp_ssect);
! 225:
! 226: /* update disklabel with details */
! 227: lp->d_partitions[0].p_size =
! 228: dp->dp_size;
! 229: lp->d_partitions[0].p_offset =
! 230: dp->dp_start;
! 231: lp->d_ntracks = dp->dp_ehd + 1;
! 232: lp->d_nsectors = DPSECT(dp->dp_esect);
! 233: lp->d_subtype |= (lp->d_subtype & 3)
! 234: + i | DSTYPE_INDOSPART;
! 235: lp->d_secpercyl = lp->d_ntracks *
! 236: lp->d_nsectors;
! 237: }
! 238: }
! 239:
! 240: }
! 241:
! 242: /* next, dig out disk label */
! 243: bp->b_blkno = dospartoff + LABELSECTOR;
! 244: bp->b_cylin = cyl;
1.1 root 245: bp->b_bcount = lp->d_secsize;
246: bp->b_flags = B_BUSY | B_READ;
247: (*strat)(bp);
1.1.1.2 ! root 248:
! 249: /* if successful, locate disk label within block and validate */
1.1 root 250: if (biowait(bp)) {
1.1.1.2 ! root 251: msg = "disk label I/O error";
! 252: goto done;
1.1 root 253: } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
254: dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
255: dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
256: if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
257: if (msg == NULL)
258: msg = "no disk label";
259: } else if (dlp->d_npartitions > MAXPARTITIONS ||
260: dkcksum(dlp) != 0)
261: msg = "disk label corrupted";
262: else {
263: *lp = *dlp;
264: msg = NULL;
265: break;
266: }
267: }
1.1.1.2 ! root 268:
! 269: if (msg)
! 270: goto done;
! 271:
! 272: /* obtain bad sector table if requested and present */
! 273: if (bdp && (lp->d_flags & D_BADSECT)) {
! 274: struct dkbad *db;
! 275:
! 276: i = 0;
! 277: do {
! 278: /* read a bad sector table */
! 279: bp->b_flags = B_BUSY | B_READ;
! 280: bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i;
! 281: if (lp->d_secsize > DEV_BSIZE)
! 282: bp->b_blkno *= lp->d_secsize / DEV_BSIZE;
! 283: else
! 284: bp->b_blkno /= DEV_BSIZE / lp->d_secsize;
! 285: bp->b_bcount = lp->d_secsize;
! 286: bp->b_cylin = lp->d_ncylinders - 1;
! 287: (*strat)(bp);
! 288:
! 289: /* if successful, validate, otherwise try another */
! 290: if (biowait(bp)) {
! 291: msg = "bad sector table I/O error";
! 292: } else {
! 293: db = (struct dkbad *)(bp->b_un.b_addr);
! 294: #define DKBAD_MAGIC 0x4321
! 295: if (db->bt_mbz == 0
! 296: && db->bt_flag == DKBAD_MAGIC) {
! 297: msg = NULL;
! 298: *bdp = *db;
! 299: break;
! 300: } else
! 301: msg = "bad sector table corrupted";
! 302: }
! 303: } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
! 304: i < lp->d_nsectors);
! 305: }
! 306:
! 307: done:
! 308: bp->b_flags = B_INVAL | B_AGE | B_READ;
! 309: #ifndef old
! 310: /* if desired, pass back allocated block so caller can use */
! 311: if (bpp)
! 312: *bpp = bp;
! 313: else
! 314: #endif
1.1 root 315: brelse(bp);
316: return (msg);
317: }
318:
319: /*
320: * Check new disk label for sensibility
321: * before setting it.
322: */
1.1.1.2 ! root 323: setdisklabel(olp, nlp, openmask, dp)
1.1 root 324: register struct disklabel *olp, *nlp;
325: u_long openmask;
1.1.1.2 ! root 326: struct dos_partition *dp;
1.1 root 327: {
328: register i;
329: register struct partition *opp, *npp;
330:
1.1.1.2 ! root 331: /* sanity clause */
! 332: if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0
! 333: || (nlp->d_secsize % DEV_BSIZE) != 0)
! 334: return(EINVAL);
! 335:
! 336: /* special case to allow disklabel to be invalidated */
! 337: if (nlp->d_magic == 0xffffffff) {
! 338: *olp = *nlp;
! 339: return (0);
! 340: }
! 341:
1.1 root 342: if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
343: dkcksum(nlp) != 0)
344: return (EINVAL);
1.1.1.2 ! root 345:
! 346: /* XXX missing check if other dos partitions will be overwritten */
! 347:
1.1 root 348: while ((i = ffs((long)openmask)) != 0) {
349: i--;
350: openmask &= ~(1 << i);
351: if (nlp->d_npartitions <= i)
352: return (EBUSY);
353: opp = &olp->d_partitions[i];
354: npp = &nlp->d_partitions[i];
355: if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
356: return (EBUSY);
357: /*
358: * Copy internally-set partition information
359: * if new label doesn't include it. XXX
360: */
361: if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
362: npp->p_fstype = opp->p_fstype;
363: npp->p_fsize = opp->p_fsize;
364: npp->p_frag = opp->p_frag;
365: npp->p_cpg = opp->p_cpg;
366: }
367: }
368: nlp->d_checksum = 0;
369: nlp->d_checksum = dkcksum(nlp);
370: *olp = *nlp;
371: return (0);
372: }
373:
374:
375: /*
376: * Write disk label back to device after modification.
377: */
1.1.1.2 ! root 378: writedisklabel(dev, strat, lp, dp)
1.1 root 379: dev_t dev;
380: int (*strat)();
381: register struct disklabel *lp;
1.1.1.2 ! root 382: struct dos_partition *dp;
1.1 root 383: {
384: struct buf *bp;
385: struct disklabel *dlp;
1.1.1.2 ! root 386: int labelpart, error = 0, dospartoff, cyl, i;
1.1 root 387:
388: labelpart = dkpart(dev);
1.1.1.2 ! root 389: #ifdef nope
1.1 root 390: if (lp->d_partitions[labelpart].p_offset != 0) {
391: if (lp->d_partitions[0].p_offset != 0)
392: return (EXDEV); /* not quite right */
393: labelpart = 0;
394: }
1.1.1.2 ! root 395: #else
! 396: labelpart = 3;
! 397: #endif
! 398:
1.1 root 399: bp = geteblk((int)lp->d_secsize);
1.1.1.2 ! root 400: /* request no partition relocation by driver on I/O operations */
! 401: bp->b_dev = makedev(major(dev), dkminor((dkunit(dev)), 3));
! 402:
! 403: /* do dos partitions in the process of getting disklabel? */
! 404: dospartoff = 0;
! 405: cyl = LABELSECTOR / lp->d_secpercyl;
! 406: if (dp) {
! 407: bp->b_blkno = DOSBBSECTOR;
! 408: bp->b_bcount = lp->d_secsize;
! 409: bp->b_flags = B_BUSY | B_READ;
! 410: bp->b_cylin = DOSBBSECTOR / lp->d_secpercyl;
! 411: (*strat)(bp);
! 412: if ((error = biowait(bp)) == 0) {
! 413: bcopy(bp->b_un.b_addr + DOSPARTOFF, dp,
! 414: NDOSPART * sizeof(*dp));
! 415: for (i = 0; i < NDOSPART; i++, dp++)
! 416: if(dp->dp_size && dp->dp_typ == DOSPTYP_386BSD
! 417: && dospartoff == 0) {
! 418: /* need sector address for SCSI/IDE,
! 419: cylinder for ESDI/ST506/RLL */
! 420: dospartoff = dp->dp_start;
! 421: cyl = dp->dp_scyl |
! 422: ((dp->dp_ssect & 0xc0) << 2);
! 423: }
! 424: }
! 425:
! 426: }
! 427:
! 428: #ifdef maybe
! 429: /* disklabel in appropriate location? */
! 430: if (lp->d_partitions[0].p_offset != 0
! 431: && lp->d_partitions[0].p_offset != dospartoff) {
! 432: error = EXDEV;
! 433: goto done;
! 434: }
! 435: #endif
! 436:
! 437: bp->b_blkno = dospartoff + LABELSECTOR;
! 438: bp->b_cylin = cyl;
1.1 root 439: bp->b_bcount = lp->d_secsize;
440: bp->b_flags = B_READ;
441: (*strat)(bp);
442: if (error = biowait(bp))
443: goto done;
444: for (dlp = (struct disklabel *)bp->b_un.b_addr;
445: dlp <= (struct disklabel *)
446: (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
447: dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
448: if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
449: dkcksum(dlp) == 0) {
450: *dlp = *lp;
451: bp->b_flags = B_WRITE;
452: (*strat)(bp);
453: error = biowait(bp);
454: goto done;
455: }
456: }
457: error = ESRCH;
458: done:
459: brelse(bp);
460: return (error);
461: }
462:
463: /*
464: * Compute checksum for disk label.
465: */
466: dkcksum(lp)
467: register struct disklabel *lp;
468: {
469: register u_short *start, *end;
470: register u_short sum = 0;
471:
472: start = (u_short *)lp;
473: end = (u_short *)&lp->d_partitions[lp->d_npartitions];
474: while (start < end)
475: sum ^= *start++;
476: return (sum);
477: }
478:
479: /*
1.1.1.2 ! root 480: * Determine the size of the transfer, and make sure it is
! 481: * within the boundaries of the partition. Adjust transfer
! 482: * if needed, and signal errors or early completion.
! 483: */
! 484: int
! 485: bounds_check_with_label(struct buf *bp, struct disklabel *lp, int wlabel)
! 486: {
! 487: struct partition *p = lp->d_partitions + dkpart(bp->b_dev);
! 488: int labelsect = lp->d_partitions[0].p_offset;
! 489: int maxsz = p->p_size,
! 490: sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
! 491:
! 492: /* overwriting disk label ? */
! 493: /* XXX should also protect bootstrap in first 8K */
! 494: if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect &&
! 495: #if LABELSECTOR != 0
! 496: bp->b_blkno + p->p_offset + sz > LABELSECTOR + labelsect &&
! 497: #endif
! 498: (bp->b_flags & B_READ) == 0 && wlabel == 0) {
! 499: bp->b_error = EROFS;
! 500: goto bad;
! 501: }
! 502:
! 503: #if defined(DOSBBSECTOR) && defined(notyet)
! 504: /* overwriting master boot record? */
! 505: if (bp->b_blkno + p->p_offset <= DOSBBSECTOR &&
! 506: (bp->b_flags & B_READ) == 0 && wlabel == 0) {
! 507: bp->b_error = EROFS;
! 508: goto bad;
! 509: }
! 510: #endif
! 511:
! 512: /* beyond partition? */
! 513: if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
! 514: /* if exactly at end of disk, return an EOF */
! 515: if (bp->b_blkno == maxsz) {
! 516: bp->b_resid = bp->b_bcount;
! 517: return(0);
! 518: }
! 519: /* or truncate if part of it fits */
! 520: sz = maxsz - bp->b_blkno;
! 521: if (sz <= 0) {
! 522: bp->b_error = EINVAL;
! 523: goto bad;
! 524: }
! 525: bp->b_bcount = sz << DEV_BSHIFT;
! 526: }
! 527:
! 528: /* calculate cylinder for disksort to order transfers with */
! 529: bp->b_cylin = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
! 530: return(1);
! 531:
! 532: bad:
! 533: bp->b_flags |= B_ERROR;
! 534: return(-1);
! 535: }
! 536:
! 537: /*
1.1 root 538: * Disk error is the preface to plaintive error messages
539: * about failing disk transfers. It prints messages of the form
540:
541: hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
542:
543: * if the offset of the error in the transfer and a disk label
544: * are both available. blkdone should be -1 if the position of the error
545: * is unknown; the disklabel pointer may be null from drivers that have not
546: * been converted to use them. The message is printed with printf
547: * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
548: * The message should be completed (with at least a newline) with printf
549: * or addlog, respectively. There is no trailing space.
550: */
1.1.1.2 ! root 551: void
1.1 root 552: diskerr(bp, dname, what, pri, blkdone, lp)
553: register struct buf *bp;
554: char *dname, *what;
555: int pri, blkdone;
556: register struct disklabel *lp;
557: {
558: int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev);
559: register void (*pr) __P((const char *, ...));
560: char partname = 'a' + part;
561: int sn;
562:
563: if (pri != LOG_PRINTF) {
564: log(pri, "");
565: pr = addlog;
566: } else
567: pr = printf;
568: (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what,
569: bp->b_flags & B_READ ? "read" : "writ");
570: sn = bp->b_blkno;
571: if (bp->b_bcount <= DEV_BSIZE)
572: (*pr)("%d", sn);
573: else {
574: if (blkdone >= 0) {
575: sn += blkdone;
576: (*pr)("%d of ", sn);
577: }
578: (*pr)("%d-%d", bp->b_blkno,
579: bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE);
580: }
581: if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
582: #ifdef tahoe
583: sn *= DEV_BSIZE / lp->d_secsize; /* XXX */
584: #endif
585: sn += lp->d_partitions[part].p_offset;
586: (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn,
587: sn / lp->d_secpercyl);
588: sn %= lp->d_secpercyl;
589: (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors);
590: }
591: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.