File:  [DragonFly] / src / sys / kern / subr_diskslice.c
Revision 1.7: download - view: text, annotated - select for diffs
Mon Nov 10 06:12:13 2003 UTC (10 years, 11 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Fully synchronize sys/boot from FreeBSD-5.x, but add / to the module path
so /kernel will be found and loaded instead of /boot/kernel.  This will
give us all the capabilities of the FreeBSD-5 boot code including AMD64 and
ELF64 support.

As part of this work, rather then try to adjust ufs/fs.h and friends to get
UFS2 info I instead copied the fs.h and friends from FreeBSD-5 into the
sys/boot subtree

Additionally, import Peter Wemm's linker set improvements from FreeBSD-5.x.
They happen to be compatible with GCC 2.95.x and it allows very few changes
to be made to the boot code.

Additionally import a number of other elements from FreeBSD-5 including
sys/diskmbr.h separation.

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