File:  [DragonFly] / src / sys / kern / subr_diskslice.c
Revision 1.8: download - view: text, annotated - select for diffs
Wed Jun 2 17:18:43 2004 UTC (10 years, 4 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Stable, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_RELEASE_1_2_Slip, DragonFly_RELEASE_1_2, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
ANSIfication and cleanup.  No functional changes.

Submitted-by: Tim Wickberg <me@k9mach3.org>

    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.82.2.6 2001/07/24 09:49:41 dd Exp $
   47:  * $DragonFly: src/sys/kern/subr_diskslice.c,v 1.8 2004/06/02 17:18:43 dillon Exp $
   48:  */
   49: 
   50: #include <sys/param.h>
   51: #include <sys/systm.h>
   52: #include <sys/buf.h>
   53: #include <sys/conf.h>
   54: #include <sys/disklabel.h>
   55: #include <sys/diskslice.h>
   56: #include <sys/diskmbr.h>
   57: #include <sys/fcntl.h>
   58: #include <sys/malloc.h>
   59: #include <sys/stat.h>
   60: #include <sys/syslog.h>
   61: #include <sys/vnode.h>
   62: #include <sys/device.h>
   63: 
   64: #include <vfs/ufs/fs.h>
   65: 
   66: #define TRACE(str)	do { if (ds_debug) printf str; } while (0)
   67: 
   68: typedef	u_char	bool_t;
   69: 
   70: static volatile bool_t ds_debug;
   71: 
   72: static struct disklabel *clone_label (struct disklabel *lp);
   73: static void dsiodone (struct buf *bp);
   74: static char *fixlabel (char *sname, struct diskslice *sp,
   75: 			   struct disklabel *lp, int writeflag);
   76: static void free_ds_label (struct diskslices *ssp, int slice);
   77: static void partition_info (char *sname, int part, struct partition *pp);
   78: static void slice_info (char *sname, struct diskslice *sp);
   79: static void set_ds_label (struct diskslices *ssp, int slice,
   80: 			      struct disklabel *lp);
   81: static void set_ds_wlabel (struct diskslices *ssp, int slice, int wlabel);
   82: 
   83: /*
   84:  * Duplicate a label for the whole disk, and initialize defaults in the
   85:  * copy for fields that are not already initialized.  The caller only
   86:  * needs to initialize d_secsize and d_secperunit, and zero the fields
   87:  * that are to be defaulted.
   88:  */
   89: static struct disklabel *
   90: clone_label(struct disklabel *lp)
   91: {
   92: 	struct disklabel *lp1;
   93: 
   94: 	lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK);
   95: 	*lp1 = *lp;
   96: 	lp = NULL;
   97: 	if (lp1->d_typename[0] == '\0')
   98: 		strncpy(lp1->d_typename, "amnesiac", sizeof(lp1->d_typename));
   99: 	if (lp1->d_packname[0] == '\0')
  100: 		strncpy(lp1->d_packname, "fictitious", sizeof(lp1->d_packname));
  101: 	if (lp1->d_nsectors == 0)
  102: 		lp1->d_nsectors = 32;
  103: 	if (lp1->d_ntracks == 0)
  104: 		lp1->d_ntracks = 64;
  105: 	lp1->d_secpercyl = lp1->d_nsectors * lp1->d_ntracks;
  106: 	lp1->d_ncylinders = lp1->d_secperunit / lp1->d_secpercyl;
  107: 	if (lp1->d_rpm == 0)
  108: 		lp1->d_rpm = 3600;
  109: 	if (lp1->d_interleave == 0)
  110: 		lp1->d_interleave = 1;
  111: 	if (lp1->d_npartitions < RAW_PART + 1)
  112: 		lp1->d_npartitions = MAXPARTITIONS;
  113: 	if (lp1->d_bbsize == 0)
  114: 		lp1->d_bbsize = BBSIZE;
  115: 	if (lp1->d_sbsize == 0)
  116: 		lp1->d_sbsize = SBSIZE;
  117: 	lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit;
  118: 	lp1->d_magic = DISKMAGIC;
  119: 	lp1->d_magic2 = DISKMAGIC;
  120: 	lp1->d_checksum = dkcksum(lp1);
  121: 	return (lp1);
  122: }
  123: 
  124: /*
  125:  * Determine the size of the transfer, and make sure it is
  126:  * within the boundaries of the partition. Adjust transfer
  127:  * if needed, and signal errors or early completion.
  128:  *
  129:  * XXX TODO:
  130:  *	o Split buffers that are too big for the device.
  131:  *	o Check for overflow.
  132:  *	o Finish cleaning this up.
  133:  */
  134: int
  135: dscheck(struct buf *bp, struct diskslices *ssp)
  136: {
  137: 	daddr_t	blkno;
  138: 	u_long	endsecno;
  139: 	daddr_t	labelsect;
  140: 	struct disklabel *lp;
  141: 	char *msg;
  142: 	long nsec;
  143: 	struct partition *pp;
  144: 	daddr_t	secno;
  145: 	daddr_t	slicerel_secno;
  146: 	struct diskslice *sp;
  147: 	int s;
  148: 
  149: 	blkno = bp->b_blkno;
  150: 	if (blkno < 0) {
  151: 		printf("dscheck(%s): negative b_blkno %ld\n", 
  152: 		    devtoname(bp->b_dev), (long)blkno);
  153: 		bp->b_error = EINVAL;
  154: 		goto bad;
  155: 	}
  156: 	sp = &ssp->dss_slices[dkslice(bp->b_dev)];
  157: 	lp = sp->ds_label;
  158: 	if (ssp->dss_secmult == 1) {
  159: 		if (bp->b_bcount % (u_long)DEV_BSIZE)
  160: 			goto bad_bcount;
  161: 		secno = blkno;
  162: 		nsec = bp->b_bcount >> DEV_BSHIFT;
  163: 	} else if (ssp->dss_secshift != -1) {
  164: 		if (bp->b_bcount & (ssp->dss_secsize - 1))
  165: 			goto bad_bcount;
  166: 		if (blkno & (ssp->dss_secmult - 1))
  167: 			goto bad_blkno;
  168: 		secno = blkno >> ssp->dss_secshift;
  169: 		nsec = bp->b_bcount >> (DEV_BSHIFT + ssp->dss_secshift);
  170: 	} else {
  171: 		if (bp->b_bcount % ssp->dss_secsize)
  172: 			goto bad_bcount;
  173: 		if (blkno % ssp->dss_secmult)
  174: 			goto bad_blkno;
  175: 		secno = blkno / ssp->dss_secmult;
  176: 		nsec = bp->b_bcount / ssp->dss_secsize;
  177: 	}
  178: 	if (lp == NULL) {
  179: 		labelsect = -LABELSECTOR - 1;
  180: 		endsecno = sp->ds_size;
  181: 		slicerel_secno = secno;
  182: 	} else {
  183: 		labelsect = lp->d_partitions[LABEL_PART].p_offset;
  184: 		if (labelsect != 0)
  185: 			Debugger("labelsect != 0 in dscheck()");
  186: 		pp = &lp->d_partitions[dkpart(bp->b_dev)];
  187: 		endsecno = pp->p_size;
  188: 		slicerel_secno = pp->p_offset + secno;
  189: 	}
  190: 
  191: 	/* overwriting disk label ? */
  192: 	/* XXX should also protect bootstrap in first 8K */
  193: 	if (slicerel_secno <= LABELSECTOR + labelsect &&
  194: #if LABELSECTOR != 0
  195: 	    slicerel_secno + nsec > LABELSECTOR + labelsect &&
  196: #endif
  197: 	    (bp->b_flags & B_READ) == 0 && sp->ds_wlabel == 0) {
  198: 		bp->b_error = EROFS;
  199: 		goto bad;
  200: 	}
  201: 
  202: #if defined(DOSBBSECTOR) && defined(notyet)
  203: 	/* overwriting master boot record? */
  204: 	if (slicerel_secno <= DOSBBSECTOR && (bp->b_flags & B_READ) == 0 &&
  205: 	    sp->ds_wlabel == 0) {
  206: 		bp->b_error = EROFS;
  207: 		goto bad;
  208: 	}
  209: #endif
  210: 
  211: 	/* beyond partition? */
  212: 	if (secno + nsec > endsecno) {
  213: 		/* if exactly at end of disk, return an EOF */
  214: 		if (secno == endsecno) {
  215: 			bp->b_resid = bp->b_bcount;
  216: 			return (0);
  217: 		}
  218: 		/* or truncate if part of it fits */
  219: 		nsec = endsecno - secno;
  220: 		if (nsec <= 0) {
  221: 			bp->b_error = EINVAL;
  222: 			goto bad;
  223: 		}
  224: 		bp->b_bcount = nsec * ssp->dss_secsize;
  225: 	}
  226: 
  227: 	bp->b_pblkno = sp->ds_offset + slicerel_secno;
  228: 
  229: 	/*
  230: 	 * Snoop on label accesses if the slice offset is nonzero.  Fudge
  231: 	 * offsets in the label to keep the in-core label coherent with
  232: 	 * the on-disk one.
  233: 	 */
  234: 	if (slicerel_secno <= LABELSECTOR + labelsect
  235: #if LABELSECTOR != 0
  236: 	    && slicerel_secno + nsec > LABELSECTOR + labelsect
  237: #endif
  238: 	    && sp->ds_offset != 0) {
  239: 		struct iodone_chain *ic;
  240: 
  241: 		ic = malloc(sizeof *ic , M_DEVBUF, M_WAITOK);
  242: 		ic->ic_prev_flags = bp->b_flags;
  243: 		ic->ic_prev_iodone = bp->b_iodone;
  244: 		ic->ic_prev_iodone_chain = bp->b_iodone_chain;
  245: 		ic->ic_args[0].ia_long = (LABELSECTOR + labelsect -
  246: 		    slicerel_secno) * ssp->dss_secsize;
  247: 		ic->ic_args[1].ia_ptr = sp;
  248: 		bp->b_flags |= B_CALL;
  249: 		bp->b_iodone = dsiodone;
  250: 		bp->b_iodone_chain = ic;
  251: 		if (!(bp->b_flags & B_READ)) {
  252: 			/*
  253: 			 * XXX even disklabel(8) writes directly so we need
  254: 			 * to adjust writes.  Perhaps we should drop support
  255: 			 * for DIOCWLABEL (always write protect labels) and
  256: 			 * require the use of DIOCWDINFO.
  257: 			 *
  258: 			 * XXX probably need to copy the data to avoid even
  259: 			 * temporarily corrupting the in-core copy.
  260: 			 */
  261: 			if (bp->b_vp != NULL) {
  262: 				s = splbio();
  263: 				bp->b_vp->v_numoutput++;
  264: 				splx(s);
  265: 			}
  266: 			/* XXX need name here. */
  267: 			msg = fixlabel((char *)NULL, sp,
  268: 				       (struct disklabel *)
  269: 				       (bp->b_data + ic->ic_args[0].ia_long),
  270: 				       TRUE);
  271: 			if (msg != NULL) {
  272: 				printf("dscheck(%s): %s\n", 
  273: 				    devtoname(bp->b_dev), msg);
  274: 				bp->b_error = EROFS;
  275: 				goto bad;
  276: 			}
  277: 		}
  278: 	}
  279: 	return (1);
  280: 
  281: bad_bcount:
  282: 	printf(
  283: 	"dscheck(%s): b_bcount %ld is not on a sector boundary (ssize %d)\n",
  284: 	    devtoname(bp->b_dev), bp->b_bcount, ssp->dss_secsize);
  285: 	bp->b_error = EINVAL;
  286: 	goto bad;
  287: 
  288: bad_blkno:
  289: 	printf(
  290: 	"dscheck(%s): b_blkno %ld is not on a sector boundary (ssize %d)\n",
  291: 	    devtoname(bp->b_dev), (long)blkno, ssp->dss_secsize);
  292: 	bp->b_error = EINVAL;
  293: 	goto bad;
  294: 
  295: bad:
  296: 	bp->b_resid = bp->b_bcount;
  297: 	bp->b_flags |= B_ERROR;
  298: 	return (-1);
  299: }
  300: 
  301: void
  302: dsclose(dev_t dev, int mode, struct diskslices *ssp)
  303: {
  304: 	u_char mask;
  305: 	struct diskslice *sp;
  306: 
  307: 	sp = &ssp->dss_slices[dkslice(dev)];
  308: 	mask = 1 << dkpart(dev);
  309: 	sp->ds_openmask &= ~mask;
  310: }
  311: 
  312: void
  313: dsgone(struct diskslices **sspp)
  314: {
  315: 	int slice;
  316: 	struct diskslice *sp;
  317: 	struct diskslices *ssp;
  318: 
  319: 	for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) {
  320: 		sp = &ssp->dss_slices[slice];
  321: 		free_ds_label(ssp, slice);
  322: 	}
  323: 	free(ssp, M_DEVBUF);
  324: 	*sspp = NULL;
  325: }
  326: 
  327: /*
  328:  * For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
  329:  * is subject to the same restriction as dsopen().
  330:  */
  331: int
  332: dsioctl(dev_t dev, u_long cmd, caddr_t data, 
  333: 	int flags, struct diskslices **sspp)
  334: {
  335: 	int error;
  336: 	struct disklabel *lp;
  337: 	int old_wlabel;
  338: 	u_char openmask;
  339: 	int part;
  340: 	int slice;
  341: 	struct diskslice *sp;
  342: 	struct diskslices *ssp;
  343: 	struct partition *pp;
  344: 
  345: 	slice = dkslice(dev);
  346: 	ssp = *sspp;
  347: 	sp = &ssp->dss_slices[slice];
  348: 	lp = sp->ds_label;
  349: 	switch (cmd) {
  350: 
  351: 	case DIOCGDVIRGIN:
  352: 		lp = (struct disklabel *)data;
  353: 		if (ssp->dss_slices[WHOLE_DISK_SLICE].ds_label) {
  354: 			*lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
  355: 		} else {
  356: 			bzero(lp, sizeof(struct disklabel));
  357: 		}
  358: 
  359: 		lp->d_magic = DISKMAGIC;
  360: 		lp->d_magic2 = DISKMAGIC;
  361: 		pp = &lp->d_partitions[RAW_PART];
  362: 		pp->p_offset = 0;
  363: 		pp->p_size = sp->ds_size;
  364: 
  365: 		lp->d_npartitions = MAXPARTITIONS;
  366: 		if (lp->d_interleave == 0)
  367: 			lp->d_interleave = 1;
  368: 		if (lp->d_rpm == 0)
  369: 			lp->d_rpm = 3600;
  370: 		if (lp->d_nsectors == 0)
  371: 			lp->d_nsectors = 32;
  372: 		if (lp->d_ntracks == 0)
  373: 			lp->d_ntracks = 64;
  374: 
  375: 		lp->d_bbsize = BBSIZE;
  376: 		lp->d_sbsize = SBSIZE;
  377: 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
  378: 		lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
  379: 		lp->d_secperunit = sp->ds_size;
  380: 		lp->d_checksum = 0;
  381: 		lp->d_checksum = dkcksum(lp);
  382: 		return (0);
  383: 
  384: 	case DIOCGDINFO:
  385: 		if (lp == NULL)
  386: 			return (EINVAL);
  387: 		*(struct disklabel *)data = *lp;
  388: 		return (0);
  389: 
  390: #ifdef notyet
  391: 	case DIOCGDINFOP:
  392: 		if (lp == NULL)
  393: 			return (EINVAL);
  394: 		*(struct disklabel **)data = lp;
  395: 		return (0);
  396: #endif
  397: 
  398: 	case DIOCGPART:
  399: 		if (lp == NULL)
  400: 			return (EINVAL);
  401: 		((struct partinfo *)data)->disklab = lp;
  402: 		((struct partinfo *)data)->part
  403: 			= &lp->d_partitions[dkpart(dev)];
  404: 		return (0);
  405: 
  406: 	case DIOCGSLICEINFO:
  407: 		bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
  408: 				 (char *)ssp);
  409: 		return (0);
  410: 
  411: 	case DIOCSDINFO:
  412: 		if (slice == WHOLE_DISK_SLICE)
  413: 			return (ENODEV);
  414: 		if (!(flags & FWRITE))
  415: 			return (EBADF);
  416: 		lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
  417: 		if (sp->ds_label == NULL)
  418: 			bzero(lp, sizeof *lp);
  419: 		else
  420: 			bcopy(sp->ds_label, lp, sizeof *lp);
  421: 		if (sp->ds_label == NULL)
  422: 			openmask = 0;
  423: 		else {
  424: 			openmask = sp->ds_openmask;
  425: 			if (slice == COMPATIBILITY_SLICE)
  426: 				openmask |= ssp->dss_slices[
  427: 				    ssp->dss_first_bsd_slice].ds_openmask;
  428: 			else if (slice == ssp->dss_first_bsd_slice)
  429: 				openmask |= ssp->dss_slices[
  430: 				    COMPATIBILITY_SLICE].ds_openmask;
  431: 		}
  432: 		error = setdisklabel(lp, (struct disklabel *)data,
  433: 				     (u_long)openmask);
  434: 		/* XXX why doesn't setdisklabel() check this? */
  435: 		if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0)
  436: 			error = EXDEV;
  437: 		if (error == 0) {
  438: 			if (lp->d_secperunit > sp->ds_size)
  439: 				error = ENOSPC;
  440: 			for (part = 0; part < lp->d_npartitions; part++)
  441: 				if (lp->d_partitions[part].p_size > sp->ds_size)
  442: 					error = ENOSPC;
  443: 		}
  444: 		if (error != 0) {
  445: 			free(lp, M_DEVBUF);
  446: 			return (error);
  447: 		}
  448: 		free_ds_label(ssp, slice);
  449: 		set_ds_label(ssp, slice, lp);
  450: 		return (0);
  451: 
  452: 	case DIOCSYNCSLICEINFO:
  453: 		if (slice != WHOLE_DISK_SLICE || dkpart(dev) != RAW_PART)
  454: 			return (EINVAL);
  455: 		if (!*(int *)data)
  456: 			for (slice = 0; slice < ssp->dss_nslices; slice++) {
  457: 				openmask = ssp->dss_slices[slice].ds_openmask;
  458: 				if (openmask
  459: 				    && (slice != WHOLE_DISK_SLICE
  460: 					|| openmask & ~(1 << RAW_PART)))
  461: 					return (EBUSY);
  462: 			}
  463: 
  464: 		/*
  465: 		 * Temporarily forget the current slices struct and read
  466: 		 * the current one.
  467: 		 * XXX should wait for current accesses on this disk to
  468: 		 * complete, then lock out future accesses and opens.
  469: 		 */
  470: 		*sspp = NULL;
  471: 		lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
  472: 		*lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
  473: 		error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, lp);
  474: 		if (error != 0) {
  475: 			free(lp, M_DEVBUF);
  476: 			*sspp = ssp;
  477: 			return (error);
  478: 		}
  479: 
  480: 		/*
  481: 		 * Reopen everything.  This is a no-op except in the "force"
  482: 		 * case and when the raw bdev and cdev are both open.  Abort
  483: 		 * if anything fails.
  484: 		 */
  485: 		for (slice = 0; slice < ssp->dss_nslices; slice++) {
  486: 			for (openmask = ssp->dss_slices[slice].ds_openmask,
  487: 			     part = 0; openmask; openmask >>= 1, part++) {
  488: 				if (!(openmask & 1))
  489: 					continue;
  490: 				error = dsopen(dkmodslice(dkmodpart(dev, part),
  491: 							  slice),
  492: 					       S_IFCHR, ssp->dss_oflags, sspp,
  493: 					       lp);
  494: 				if (error != 0) {
  495: 					free(lp, M_DEVBUF);
  496: 					*sspp = ssp;
  497: 					return (EBUSY);
  498: 				}
  499: 			}
  500: 		}
  501: 
  502: 		free(lp, M_DEVBUF);
  503: 		dsgone(&ssp);
  504: 		return (0);
  505: 
  506: 	case DIOCWDINFO:
  507: 		error = dsioctl(dev, DIOCSDINFO, data, flags, &ssp);
  508: 		if (error != 0)
  509: 			return (error);
  510: 		/*
  511: 		 * XXX this used to hack on dk_openpart to fake opening
  512: 		 * partition 0 in case that is used instead of dkpart(dev).
  513: 		 */
  514: 		old_wlabel = sp->ds_wlabel;
  515: 		set_ds_wlabel(ssp, slice, TRUE);
  516: 		error = writedisklabel(dev, sp->ds_label);
  517: 		/* XXX should invalidate in-core label if write failed. */
  518: 		set_ds_wlabel(ssp, slice, old_wlabel);
  519: 		return (error);
  520: 
  521: 	case DIOCWLABEL:
  522: #ifndef __alpha__
  523: 		if (slice == WHOLE_DISK_SLICE)
  524: 			return (ENODEV);
  525: #endif
  526: 		if (!(flags & FWRITE))
  527: 			return (EBADF);
  528: 		set_ds_wlabel(ssp, slice, *(int *)data != 0);
  529: 		return (0);
  530: 
  531: 	default:
  532: 		return (ENOIOCTL);
  533: 	}
  534: }
  535: 
  536: static void
  537: dsiodone(struct buf *bp)
  538: {
  539: 	struct iodone_chain *ic;
  540: 	char *msg;
  541: 
  542: 	ic = bp->b_iodone_chain;
  543: 	bp->b_flags = (ic->ic_prev_flags & B_CALL)
  544: 		      | (bp->b_flags & ~(B_CALL | B_DONE));
  545: 	bp->b_iodone = ic->ic_prev_iodone;
  546: 	bp->b_iodone_chain = ic->ic_prev_iodone_chain;
  547: 	if (!(bp->b_flags & B_READ)
  548: 	    || (!(bp->b_flags & B_ERROR) && bp->b_error == 0)) {
  549: 		msg = fixlabel((char *)NULL, ic->ic_args[1].ia_ptr,
  550: 			       (struct disklabel *)
  551: 			       (bp->b_data + ic->ic_args[0].ia_long),
  552: 			       FALSE);
  553: 		if (msg != NULL)
  554: 			printf("%s\n", msg);
  555: 	}
  556: 	free(ic, M_DEVBUF);
  557: 	biodone(bp);
  558: }
  559: 
  560: int
  561: dsisopen(struct diskslices *ssp)
  562: {
  563: 	int slice;
  564: 
  565: 	if (ssp == NULL)
  566: 		return (0);
  567: 	for (slice = 0; slice < ssp->dss_nslices; slice++) {
  568: 		if (ssp->dss_slices[slice].ds_openmask)
  569: 			return (1);
  570: 	}
  571: 	return (0);
  572: }
  573: 
  574: /*
  575:  * Allocate a slices "struct" and initialize it to contain only an empty
  576:  * compatibility slice (pointing to itself), a whole disk slice (covering
  577:  * the disk as described by the label), and (nslices - BASE_SLICES) empty
  578:  * slices beginning at BASE_SLICE.
  579:  */
  580: struct diskslices *
  581: dsmakeslicestruct(int nslices, struct disklabel *lp)
  582: {
  583: 	struct diskslice *sp;
  584: 	struct diskslices *ssp;
  585: 
  586: 	ssp = malloc(offsetof(struct diskslices, dss_slices) +
  587: 		     nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
  588: 	ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
  589: 	ssp->dss_nslices = nslices;
  590: 	ssp->dss_oflags = 0;
  591: 	ssp->dss_secmult = lp->d_secsize / DEV_BSIZE;
  592: 	if (ssp->dss_secmult & (ssp->dss_secmult - 1))
  593: 		ssp->dss_secshift = -1;
  594: 	else
  595: 		ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
  596: 	ssp->dss_secsize = lp->d_secsize;
  597: 	sp = &ssp->dss_slices[0];
  598: 	bzero(sp, nslices * sizeof *sp);
  599: 	sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit;
  600: 	return (ssp);
  601: }
  602: 
  603: char *
  604: dsname(dev_t dev, int unit, int slice, int part, char *partname)
  605: {
  606: 	static char name[32];
  607: 	const char *dname;
  608: 
  609: 	dname = dev_dname(dev);
  610: 	if (strlen(dname) > 16)
  611: 		dname = "nametoolong";
  612: 	snprintf(name, sizeof(name), "%s%d", dname, unit);
  613: 	partname[0] = '\0';
  614: 	if (slice != WHOLE_DISK_SLICE || part != RAW_PART) {
  615: 		partname[0] = 'a' + part;
  616: 		partname[1] = '\0';
  617: 		if (slice != COMPATIBILITY_SLICE) {
  618: 			snprintf(name + strlen(name),
  619: 			    sizeof(name) - strlen(name), "s%d", slice - 1);
  620: 		}
  621: 	}
  622: 	return (name);
  623: }
  624: 
  625: /*
  626:  * This should only be called when the unit is inactive and the strategy
  627:  * routine should not allow it to become active unless we call it.  Our
  628:  * strategy routine must be special to allow activity.
  629:  */
  630: int
  631: dsopen(dev_t dev, int mode, u_int flags, 
  632: 	struct diskslices **sspp, struct disklabel *lp)
  633: {
  634: 	dev_t dev1;
  635: 	int error;
  636: 	struct disklabel *lp1;
  637: 	char *msg;
  638: 	u_char mask;
  639: 	bool_t need_init;
  640: 	int part;
  641: 	char partname[2];
  642: 	int slice;
  643: 	char *sname;
  644: 	struct diskslice *sp;
  645: 	struct diskslices *ssp;
  646: 	int unit;
  647: 
  648: 	dev->si_bsize_phys = lp->d_secsize;
  649: 
  650: 	unit = dkunit(dev);
  651: 	if (lp->d_secsize % DEV_BSIZE) {
  652: 		printf("%s: invalid sector size %lu\n", devtoname(dev),
  653: 		    (u_long)lp->d_secsize);
  654: 		return (EINVAL);
  655: 	}
  656: 
  657: 	/*
  658: 	 * XXX reinitialize the slice table unless there is an open device
  659: 	 * on the unit.  This should only be done if the media has changed.
  660: 	 */
  661: 	ssp = *sspp;
  662: 	need_init = !dsisopen(ssp);
  663: 	if (ssp != NULL && need_init)
  664: 		dsgone(sspp);
  665: 	if (need_init) {
  666: 		/*
  667: 		 * Allocate a minimal slices "struct".  This will become
  668: 		 * the final slices "struct" if we don't want real slices
  669: 		 * or if we can't find any real slices.
  670: 		 */
  671: 		*sspp = dsmakeslicestruct(BASE_SLICE, lp);
  672: 
  673: 		if (!(flags & DSO_ONESLICE)) {
  674: 			TRACE(("dsinit\n"));
  675: 			error = dsinit(dev, lp, sspp);
  676: 			if (error != 0) {
  677: 				dsgone(sspp);
  678: 				return (error);
  679: 			}
  680: 		}
  681: 		ssp = *sspp;
  682: 		ssp->dss_oflags = flags;
  683: 
  684: 		/*
  685: 		 * If there are no real slices, then make the compatiblity
  686: 		 * slice cover the whole disk.
  687: 		 */
  688: 		if (ssp->dss_nslices == BASE_SLICE)
  689: 			ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
  690: 				= lp->d_secperunit;
  691: 
  692: 		/* Point the compatibility slice at the BSD slice, if any. */
  693: 		for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
  694: 			sp = &ssp->dss_slices[slice];
  695: 			if (sp->ds_type == DOSPTYP_386BSD /* XXX */) {
  696: 				ssp->dss_first_bsd_slice = slice;
  697: 				ssp->dss_slices[COMPATIBILITY_SLICE].ds_offset
  698: 					= sp->ds_offset;
  699: 				ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
  700: 					= sp->ds_size;
  701: 				ssp->dss_slices[COMPATIBILITY_SLICE].ds_type
  702: 					= sp->ds_type;
  703: 				break;
  704: 			}
  705: 		}
  706: 
  707: 		ssp->dss_slices[WHOLE_DISK_SLICE].ds_label = clone_label(lp);
  708: 		ssp->dss_slices[WHOLE_DISK_SLICE].ds_wlabel = TRUE;
  709: 	}
  710: 
  711: 	/*
  712: 	 * Initialize secondary info for all slices.  It is needed for more
  713: 	 * than the current slice in the DEVFS case.  XXX DEVFS is no more.
  714: 	 */
  715: 	for (slice = 0; slice < ssp->dss_nslices; slice++) {
  716: 		sp = &ssp->dss_slices[slice];
  717: 		if (sp->ds_label != NULL
  718: #ifdef __alpha__
  719: 		    && slice != WHOLE_DISK_SLICE
  720: #endif
  721: 		    )
  722: 			continue;
  723: 		dev1 = dkmodslice(dkmodpart(dev, RAW_PART), slice);
  724: 		sname = dsname(dev, unit, slice, RAW_PART, partname);
  725: 		/*
  726: 		 * XXX this should probably only be done for the need_init
  727: 		 * case, but there may be a problem with DIOCSYNCSLICEINFO.
  728: 		 */
  729: 		set_ds_wlabel(ssp, slice, TRUE);	/* XXX invert */
  730: 		lp1 = clone_label(lp);
  731: 		TRACE(("readdisklabel\n"));
  732: 		if (flags & DSO_NOLABELS)
  733: 			msg = NULL;
  734: 		else {
  735: 			msg = readdisklabel(dev1, lp1);
  736: 
  737: 			/*
  738: 			 * readdisklabel() returns NULL for success, and an
  739: 			 * error string for failure.
  740: 			 *
  741: 			 * If there isn't a label on the disk, and if the
  742: 			 * DSO_COMPATLABEL is set, we want to use the
  743: 			 * faked-up label provided by the caller.
  744: 			 *
  745: 			 * So we set msg to NULL to indicate that there is
  746: 			 * no failure (since we have a faked-up label),
  747: 			 * free lp1, and then clone it again from lp.
  748: 			 * (In case readdisklabel() modified lp1.)
  749: 			 */
  750: 			if (msg != NULL && (flags & DSO_COMPATLABEL)) {
  751: 				msg = NULL;
  752: 				free(lp1, M_DEVBUF);
  753: 				lp1 = clone_label(lp);
  754: 			}
  755: 		}
  756: 		if (msg == NULL)
  757: 			msg = fixlabel(sname, sp, lp1, FALSE);
  758: 		if (msg == NULL && lp1->d_secsize != ssp->dss_secsize)
  759: 			msg = "inconsistent sector size";
  760: 		if (msg != NULL) {
  761: 			if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
  762: 				log(LOG_WARNING, "%s: cannot find label (%s)\n",
  763: 				    sname, msg);
  764: 			free(lp1, M_DEVBUF);
  765: 			continue;
  766: 		}
  767: 		if (lp1->d_flags & D_BADSECT) {
  768: 			log(LOG_ERR, "%s: bad sector table not supported\n",
  769: 			    sname);
  770: 			free(lp1, M_DEVBUF);
  771: 			continue;
  772: 		}
  773: 		set_ds_label(ssp, slice, lp1);
  774: 		set_ds_wlabel(ssp, slice, FALSE);
  775: 	}
  776: 
  777: 	slice = dkslice(dev);
  778: 	if (slice >= ssp->dss_nslices)
  779: 		return (ENXIO);
  780: 	sp = &ssp->dss_slices[slice];
  781: 	part = dkpart(dev);
  782: 	if (part != RAW_PART
  783: 	    && (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions))
  784: 		return (EINVAL);	/* XXX needs translation */
  785: 	mask = 1 << part;
  786: 	sp->ds_openmask |= mask;
  787: 	return (0);
  788: }
  789: 
  790: int
  791: dssize(dev_t dev, struct diskslices **sspp)
  792: {
  793: 	struct disklabel *lp;
  794: 	int part;
  795: 	int slice;
  796: 	struct diskslices *ssp;
  797: 
  798: 	slice = dkslice(dev);
  799: 	part = dkpart(dev);
  800: 	ssp = *sspp;
  801: 	if (ssp == NULL || slice >= ssp->dss_nslices
  802: 	    || !(ssp->dss_slices[slice].ds_openmask & (1 << part))) {
  803: 		if (dev_dopen(dev, FREAD, S_IFCHR, NULL) != 0)
  804: 			return (-1);
  805: 		dev_dclose(dev, FREAD, S_IFCHR, NULL);
  806: 		ssp = *sspp;
  807: 	}
  808: 	lp = ssp->dss_slices[slice].ds_label;
  809: 	if (lp == NULL)
  810: 		return (-1);
  811: 	return ((int)lp->d_partitions[part].p_size);
  812: }
  813: 
  814: static void
  815: free_ds_label(struct diskslices *ssp, int slice)
  816: {
  817: 	struct disklabel *lp;
  818: 	struct diskslice *sp;
  819: 
  820: 	sp = &ssp->dss_slices[slice];
  821: 	lp = sp->ds_label;
  822: 	if (lp == NULL)
  823: 		return;
  824: 	free(lp, M_DEVBUF);
  825: 	set_ds_label(ssp, slice, (struct disklabel *)NULL);
  826: }
  827: 
  828: static char *
  829: fixlabel(char *sname, struct diskslice *sp, struct disklabel *lp, int writeflag)
  830: {
  831: 	u_long end;
  832: 	u_long offset;
  833: 	int part;
  834: 	struct partition *pp;
  835: 	u_long start;
  836: 	bool_t warned;
  837: 
  838: 	/* These errors "can't happen" so don't bother reporting details. */
  839: 	if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC)
  840: 		return ("fixlabel: invalid magic");
  841: 	if (dkcksum(lp) != 0)
  842: 		return ("fixlabel: invalid checksum");
  843: 
  844: 	pp = &lp->d_partitions[RAW_PART];
  845: 	if (writeflag) {
  846: 		start = 0;
  847: 		offset = sp->ds_offset;
  848: 	} else {
  849: 		start = sp->ds_offset;
  850: 		offset = -sp->ds_offset;
  851: 	}
  852: 	if (pp->p_offset != start) {
  853: 		if (sname != NULL) {
  854: 			printf(
  855: "%s: rejecting BSD label: raw partition offset != slice offset\n",
  856: 			       sname);
  857: 			slice_info(sname, sp);
  858: 			partition_info(sname, RAW_PART, pp);
  859: 		}
  860: 		return ("fixlabel: raw partition offset != slice offset");
  861: 	}
  862: 	if (pp->p_size != sp->ds_size) {
  863: 		if (sname != NULL) {
  864: 			printf("%s: raw partition size != slice size\n", sname);
  865: 			slice_info(sname, sp);
  866: 			partition_info(sname, RAW_PART, pp);
  867: 		}
  868: 		if (pp->p_size > sp->ds_size) {
  869: 			if (sname == NULL)
  870: 				return ("fixlabel: raw partition size > slice size");
  871: 			printf("%s: truncating raw partition\n", sname);
  872: 			pp->p_size = sp->ds_size;
  873: 		}
  874: 	}
  875: 	end = start + sp->ds_size;
  876: 	if (start > end)
  877: 		return ("fixlabel: slice wraps");
  878: 	if (lp->d_secpercyl <= 0)
  879: 		return ("fixlabel: d_secpercyl <= 0");
  880: 	pp -= RAW_PART;
  881: 	warned = FALSE;
  882: 	for (part = 0; part < lp->d_npartitions; part++, pp++) {
  883: 		if (pp->p_offset != 0 || pp->p_size != 0) {
  884: 			if (pp->p_offset < start
  885: 			    || pp->p_offset + pp->p_size > end
  886: 			    || pp->p_offset + pp->p_size < pp->p_offset) {
  887: 				if (sname != NULL) {
  888: 					printf(
  889: "%s: rejecting partition in BSD label: it isn't entirely within the slice\n",
  890: 					       sname);
  891: 					if (!warned) {
  892: 						slice_info(sname, sp);
  893: 						warned = TRUE;
  894: 					}
  895: 					partition_info(sname, part, pp);
  896: 				}
  897: 				/* XXX else silently discard junk. */
  898: 				bzero(pp, sizeof *pp);
  899: 			} else
  900: 				pp->p_offset += offset;
  901: 		}
  902: 	}
  903: 	lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
  904: 	lp->d_secperunit = sp->ds_size;
  905:  	lp->d_checksum = 0;
  906:  	lp->d_checksum = dkcksum(lp);
  907: 	return (NULL);
  908: }
  909: 
  910: static void
  911: partition_info(char *sname, int part, struct partition *pp)
  912: {
  913: 	printf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part,
  914: 	       (u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1),
  915: 	       (u_long)pp->p_size);
  916: }
  917: 
  918: static void
  919: slice_info(char *sname, struct diskslice *sp)
  920: {
  921: 	printf("%s: start %lu, end %lu, size %lu\n", sname,
  922: 	       sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size);
  923: }
  924: 
  925: static void
  926: set_ds_label(struct diskslices *ssp, int slice, struct disklabel *lp)
  927: {
  928: 	ssp->dss_slices[slice].ds_label = lp;
  929: 	if (slice == COMPATIBILITY_SLICE)
  930: 		ssp->dss_slices[ssp->dss_first_bsd_slice].ds_label = lp;
  931: 	else if (slice == ssp->dss_first_bsd_slice)
  932: 		ssp->dss_slices[COMPATIBILITY_SLICE].ds_label = lp;
  933: }
  934: 
  935: static void
  936: set_ds_wlabel(struct diskslices *ssp, int slice, int wlabel)
  937: {
  938: 	ssp->dss_slices[slice].ds_wlabel = wlabel;
  939: 	if (slice == COMPATIBILITY_SLICE)
  940: 		ssp->dss_slices[ssp->dss_first_bsd_slice].ds_wlabel = wlabel;
  941: 	else if (slice == ssp->dss_first_bsd_slice)
  942: 		ssp->dss_slices[COMPATIBILITY_SLICE].ds_wlabel = wlabel;
  943: }