1: /* 2: * Copyright (c) 1982, 1986, 1988, 1993 3: * The Regents of the University of California. All rights reserved. 4: * (c) UNIX System Laboratories, Inc. 5: * All or some portions of this file are derived from material licensed 6: * to the University of California by American Telephone and Telegraph 7: * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8: * the permission of UNIX System Laboratories, Inc. 9: * 10: * Redistribution and use in source and binary forms, with or without 11: * modification, are permitted provided that the following conditions 12: * are met: 13: * 1. Redistributions of source code must retain the above copyright 14: * notice, this list of conditions and the following disclaimer. 15: * 2. Redistributions in binary form must reproduce the above copyright 16: * notice, this list of conditions and the following disclaimer in the 17: * documentation and/or other materials provided with the distribution. 18: * 3. All advertising materials mentioning features or use of this software 19: * must display the following acknowledgement: 20: * This product includes software developed by the University of 21: * California, Berkeley and its contributors. 22: * 4. Neither the name of the University nor the names of its contributors 23: * may be used to endorse or promote products derived from this software 24: * without specific prior written permission. 25: * 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36: * SUCH DAMAGE. 37: * 38: * @(#)ufs_disksubr.c 8.5.5 (2.11BSD GTE) 1998/4/3 39: */ 40: 41: #include <errno.h> 42: #include <syslog.h> 43: #include <sys/param.h> 44: #include <sys/user.h> 45: #include <sys/systm.h> 46: #include <machine/seg.h> 47: #include <sys/buf.h> 48: #include <sys/file.h> 49: #include <sys/ioctl.h> 50: #include <sys/disklabel.h> 51: #include <sys/disk.h> 52: 53: /* 54: * Attempt to read a disk label from a device using the indicated stategy 55: * routine. The label must be partly set up before this: secpercyl and 56: * anything required in the strategy routine (e.g., sector size) must be 57: * filled in before calling us. Returns NULL on success and an error 58: * string on failure. 59: */ 60: char * 61: readdisklabel(dev, strat, lp) 62: dev_t dev; 63: int (*strat)(); 64: register struct disklabel *lp; 65: { 66: register struct buf *bp; 67: struct disklabel *dlp; 68: char *msg = NULL; 69: 70: if (lp->d_secperunit == 0) 71: lp->d_secperunit = 0x1fffffffL; 72: lp->d_npartitions = 1; 73: if (lp->d_partitions[0].p_size == 0) 74: lp->d_partitions[0].p_size = 0x1fffffffL; 75: lp->d_partitions[0].p_offset = 0; 76: 77: bp = geteblk(); 78: bp->b_dev = dev; 79: bp->b_blkno = LABELSECTOR; 80: bp->b_bcount = lp->d_secsize; /* Probably should wire this to 512 */ 81: bp->b_flags = B_BUSY | B_READ; 82: bp->b_cylin = LABELSECTOR / lp->d_secpercyl; 83: (*strat)(bp); 84: biowait(bp); 85: if (u.u_error) 86: msg = "I/O error"; 87: else 88: { 89: dlp = (struct disklabel *)mapin(bp); 90: if (dlp->d_magic != DISKMAGIC || 91: dlp->d_magic2 != DISKMAGIC) 92: { 93: if (msg == NULL) 94: msg = "no disk label"; 95: } 96: else if (dlp->d_npartitions > MAXPARTITIONS || dkcksum(dlp)) 97: msg = "disk label corrupted"; 98: else 99: bcopy(dlp, lp, sizeof (struct disklabel)); 100: mapout(bp); 101: } 102: bp->b_flags = B_INVAL | B_AGE; 103: brelse(bp); 104: return(msg); 105: } 106: 107: /* 108: * Check new disk label for sensibility before setting it. 'olp' must point 109: * to a kernel resident (or mapped in) label. 'nlp' points to the new label 110: * usually present on the stack (having been passed in via ioctl from an 111: * application). 112: */ 113: int 114: setdisklabel(olp, nlp, openmask) 115: struct disklabel *olp; 116: register struct disklabel *nlp; 117: u_short openmask; 118: { 119: int i; 120: register struct partition *opp, *npp; 121: 122: if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 123: dkcksum(nlp) != 0) 124: return (EINVAL); 125: while ((i = ffs((long)openmask)) != 0) { 126: i--; 127: openmask &= ~(1 << i); 128: if (nlp->d_npartitions <= i) 129: return (EBUSY); 130: opp = &olp->d_partitions[i]; 131: npp = &nlp->d_partitions[i]; 132: if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 133: return (EBUSY); 134: /* 135: * Copy internally-set partition information 136: * if new label doesn't include it. XXX 137: */ 138: if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 139: npp->p_fstype = opp->p_fstype; 140: npp->p_fsize = opp->p_fsize; 141: npp->p_frag = opp->p_frag; 142: } 143: } 144: nlp->d_checksum = 0; 145: nlp->d_checksum = dkcksum(nlp); 146: bcopy(nlp, olp, sizeof (struct disklabel)); 147: return (0); 148: } 149: 150: /* 151: * Write disk label back to device after modification. 152: */ 153: int 154: writedisklabel(dev, strat, lp) 155: dev_t dev; 156: int (*strat)(); 157: register struct disklabel *lp; 158: { 159: struct buf *bp; 160: struct disklabel *dlp; 161: int labelpart; 162: int error = 0; 163: 164: labelpart = dkpart(dev); 165: if (lp->d_partitions[labelpart].p_offset != 0) { 166: if (lp->d_partitions[0].p_offset != 0) 167: return (EXDEV); /* not quite right */ 168: labelpart = 0; 169: } 170: bp = geteblk(); 171: bp->b_dev = makedev(major(dev), dkminor(dkunit(dev), labelpart)); 172: bp->b_blkno = LABELSECTOR; 173: bp->b_bcount = lp->d_secsize; /* probably should wire to 512 */ 174: bp->b_flags = B_READ; 175: (*strat)(bp); 176: biowait(bp); 177: if (u.u_error) 178: goto done; 179: dlp = (struct disklabel *)mapin(bp); 180: if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 181: dkcksum(dlp) == 0) { 182: bcopy(lp, dlp, sizeof (struct disklabel)); 183: mapout(bp); 184: bp->b_flags = B_WRITE; 185: (*strat)(bp); 186: biowait(bp); 187: error = u.u_error; 188: } else { 189: error = ESRCH; 190: mapout(bp); 191: } 192: done: 193: brelse(bp); 194: return(error); 195: } 196: 197: /* 198: * Compute checksum for disk label. 199: */ 200: dkcksum(lp) 201: struct disklabel *lp; 202: { 203: register u_short *start, *end; 204: register u_short sum = 0; 205: 206: start = (u_short *)lp; 207: end = (u_short *)&lp->d_partitions[lp->d_npartitions]; 208: while (start < end) 209: sum ^= *start++; 210: return (sum); 211: } 212: 213: /* 214: * This is new for 2.11BSD. It is a common routine that checks for 215: * opening a partition that overlaps other currently open partitions. 216: * 217: * NOTE: if 'c' is not the entire drive (as is the case with the old, 218: * nonstandard, haphazard and overlapping partition tables) the warning 219: * message will be erroneously issued in some valid situations. 220: */ 221: 222: #define RAWPART 2 /* 'c' */ /* XXX */ 223: 224: dkoverlapchk(openmask, dev, label, name) 225: int openmask; 226: dev_t dev; 227: memaddr label; 228: char *name; 229: { 230: int unit = dkunit(dev); 231: int part = dkpart(dev); 232: int partmask = 1 << part; 233: int i; 234: daddr_t start, end; 235: register struct disklabel *lp = (struct disklabel *)SEG5; 236: register struct partition *pp; 237: 238: if ((openmask & partmask) == 0 && part != RAWPART) 239: { 240: mapseg5(label, LABELDESC); 241: pp = &lp->d_partitions[part]; 242: start = pp->p_offset; 243: end = pp->p_offset + pp->p_size; 244: i = 0; 245: for (pp = lp->d_partitions; i < lp->d_npartitions; pp++,i++) 246: { 247: if (pp->p_offset + pp->p_size <= start || 248: pp->p_offset >= end || i == RAWPART) 249: continue; 250: if (openmask & (1 << i)) 251: log(LOG_WARNING, 252: "%s%d%c: overlaps open part (%c)\n", 253: name, unit, part + 'a', i + 'a'); 254: } 255: normalseg5(); 256: } 257: return(0); 258: } 259: 260: /* 261: * It was noticed that the ioctl processing of disklabels was the same 262: * for every disk driver. Disk drivers should call this routine after 263: * handling ioctls (if any) particular to themselves. 264: */ 265: 266: ioctldisklabel(dev, cmd, data, flag, disk, strat) 267: dev_t dev; 268: int cmd; 269: register caddr_t data; 270: int flag; 271: register struct dkdevice *disk; 272: int (*strat)(); 273: { 274: struct disklabel label; 275: register struct disklabel *lp = &label; 276: int error; 277: int flags; 278: 279: /* 280: * Copy in mapped out label to the local copy on the stack. We're in the 281: * high kernel at this point so saving the mapping is not necessary. 282: */ 283: mapseg5(disk->dk_label, LABELDESC); 284: bcopy((struct disklabel *)SEG5, lp, sizeof (*lp)); 285: normalseg5(); 286: 287: switch (cmd) 288: { 289: case DIOCGDINFO: 290: bcopy(lp, (struct disklabel *)data, sizeof (*lp)); 291: return(0); 292: /* 293: * Used internally by the kernel in init_main to verify that 'swapdev' 294: * is indeed a FS_SWAP partition. 295: * 296: * NOTE: the label address is the external click address! 297: */ 298: case DIOCGPART: 299: ((struct partinfo *)data)->disklab = 300: (struct disklabel *)disk->dk_label; 301: ((struct partinfo *)data)->part = 302: &disk->dk_parts[dkpart(dev)]; 303: return(0); 304: case DIOCWLABEL: 305: if ((flag & FWRITE) == 0) 306: return(EBADF); 307: if (*(int *)data) 308: disk->dk_flags |= DKF_WLABEL; 309: else 310: disk->dk_flags &= ~DKF_WLABEL; 311: return(0); 312: case DIOCSDINFO: 313: if ((flag & FWRITE) == 0) 314: return(EBADF); 315: error = setdisklabel(lp, (struct disklabel *)data, 316: disk->dk_flags & DKF_WLABEL ? 0 317: : disk->dk_openmask); 318: /* 319: * If no error was encountered setting the disklabel then we must copy 320: * out the new label from the local copy to the mapped out label. Also 321: * update the partition tables (which are resident in the kernel). 322: */ 323: if (error == 0) 324: { 325: mapseg5(disk->dk_label, LABELDESC); 326: bcopy(lp,(struct disklabel *)SEG5,sizeof (*lp)); 327: normalseg5(); 328: bcopy(&lp->d_partitions, &disk->dk_parts, 329: sizeof (lp->d_partitions)); 330: } 331: return(error); 332: case DIOCWDINFO: 333: if ((flag & FWRITE) == 0) 334: return(EBADF); 335: error = setdisklabel(lp, (struct disklabel *)data, 336: disk->dk_flags & DKF_WLABEL ? 0 337: : disk->dk_openmask); 338: if (error) 339: return(error); 340: /* 341: * Copy to external label. Ah - need to also update the kernel resident 342: * partition tables! 343: */ 344: mapseg5(disk->dk_label, LABELDESC); 345: bcopy(lp,(struct disklabel *)SEG5,sizeof (*lp)); 346: normalseg5(); 347: bcopy(&lp->d_partitions, &disk->dk_parts, 348: sizeof (lp->d_partitions)); 349: 350: /* 351: * We use the 'a' partition to write the label. This probably shouldn't 352: * be wired in here but it's not worth creating another macro for. Is it? 353: * The flags are faked to write enable the label area and that the drive is 354: * alive - it better be at this point or there is a problem in the open routine. 355: */ 356: flags = disk->dk_flags; 357: disk->dk_flags |= (DKF_ALIVE | DKF_WLABEL); 358: error = writedisklabel(dev & ~7, strat, lp); 359: disk->dk_flags = flags; 360: return(error); 361: } 362: return(EINVAL); 363: } 364: 365: 366: /* 367: * This was extracted from the MSCP driver so it could be shared between 368: * all disk drivers which implement disk labels. 369: */ 370: 371: partition_check(bp, dk) 372: struct buf *bp; 373: struct dkdevice *dk; 374: { 375: struct partition *pi; 376: daddr_t sz; 377: 378: pi = &dk->dk_parts[dkpart(bp->b_dev)]; 379: 380: /* Valid block in device partition */ 381: sz = (bp->b_bcount + 511) >> 9; 382: if (bp->b_blkno < 0 || bp->b_blkno + sz > pi->p_size) 383: { 384: sz = pi->p_size - bp->b_blkno; 385: /* if exactly at end of disk, return an EOF */ 386: if (sz == 0) 387: { 388: bp->b_resid = bp->b_bcount; 389: goto done; 390: } 391: /* or truncate if part of it fits */ 392: if (sz < 0) 393: { 394: bp->b_error = EINVAL; 395: goto bad; 396: } 397: bp->b_bcount = dbtob(sz); /* compute byte count */ 398: } 399: /* 400: * Check for write to write-protected label area. This does not include 401: * sector 0 which is the boot block. 402: */ 403: if (bp->b_blkno + pi->p_offset <= LABELSECTOR && 404: bp->b_blkno + pi->p_offset + sz > LABELSECTOR && 405: !(bp->b_flags & B_READ) && !(dk->dk_flags & DKF_WLABEL)) 406: { 407: bp->b_error = EROFS; 408: goto bad; 409: } 410: return(1); /* success */ 411: bad: 412: return(-1); 413: done: 414: return(0); 415: }