diff options
Diffstat (limited to 'sys/kern/subr_diskslice.c')
-rw-r--r-- | sys/kern/subr_diskslice.c | 870 |
1 files changed, 870 insertions, 0 deletions
diff --git a/sys/kern/subr_diskslice.c b/sys/kern/subr_diskslice.c new file mode 100644 index 0000000..5555a81 --- /dev/null +++ b/sys/kern/subr_diskslice.c @@ -0,0 +1,870 @@ +/*- + * Copyright (c) 1994 Bruce D. Evans. + * All rights reserved. + * + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 + * from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $ + * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 + * from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $ + * $Id: subr_diskslice.c,v 1.14 1995/05/30 08:05:51 rgrimes Exp $ + */ + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/disklabel.h> +#include <sys/diskslice.h> +#include <sys/dkbad.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/stat.h> +#include <sys/syslog.h> +#include <sys/systm.h> +#include <sys/vnode.h> + +#define b_cylinder b_resid + +#define FALSE 0 +#define TRUE 1 + +#define TRACE(str) do { if (ds_debug) printf str; } while (0) + +typedef u_char bool_t; + +static volatile bool_t ds_debug; + +static void dsiodone __P((struct buf *bp)); +static char *fixlabel __P((char *sname, struct diskslice *sp, + struct disklabel *lp, int writeflag)); +static void partition_info __P((char *sname, int part, struct partition *pp)); +static void slice_info __P((char *sname, struct diskslice *sp)); +static void set_ds_bad __P((struct diskslices *ssp, int slice, + struct dkbad_intern *btp)); +static void set_ds_label __P((struct diskslices *ssp, int slice, + struct disklabel *lp)); +static void set_ds_wlabel __P((struct diskslices *ssp, int slice, + int wlabel)); + +/* + * Determine the size of the transfer, and make sure it is + * within the boundaries of the partition. Adjust transfer + * if needed, and signal errors or early completion. + * + * XXX TODO: + * o Do bad sector remapping. May need to split buffer. + * o Split buffers that are too big for the device. + * o Check for overflow. + * o Finish cleaning this up. + */ +int +dscheck(bp, ssp) + struct buf *bp; + struct diskslices *ssp; +{ + daddr_t blkno; + daddr_t labelsect; + struct disklabel *lp; + u_long maxsz; + char *msg; + struct partition *pp; + struct diskslice *sp; + long sz; + + sp = &ssp->dss_slices[dkslice(bp->b_dev)]; + lp = sp->ds_label; + sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; + if (lp == NULL) { + blkno = bp->b_blkno; + labelsect = -LABELSECTOR - 1; + maxsz = sp->ds_size; + } else { + labelsect = lp->d_partitions[LABEL_PART].p_offset; +if (labelsect != 0) Debugger("labelsect != 0 in dscheck()"); + pp = &lp->d_partitions[dkpart(bp->b_dev)]; + blkno = pp->p_offset + bp->b_blkno; + maxsz = pp->p_size; + if (sp->ds_bad != NULL && ds_debug) { + daddr_t newblkno; + + newblkno = transbad144(sp->ds_bad, blkno); + if (newblkno != blkno) + printf("should map bad block %lu -> %lu\n", + blkno, newblkno); + } + } + + /* overwriting disk label ? */ + /* XXX should also protect bootstrap in first 8K */ + if (blkno <= LABELSECTOR + labelsect && +#if LABELSECTOR != 0 + bp->b_blkno + sz > LABELSECTOR + labelsect && +#endif + (bp->b_flags & B_READ) == 0 && sp->ds_wlabel == 0) { + bp->b_error = EROFS; + goto bad; + } + +#if defined(DOSBBSECTOR) && defined(notyet) + /* overwriting master boot record? */ + if (blkno <= DOSBBSECTOR && (bp->b_flags & B_READ) == 0 && + sp->ds_wlabel == 0) { + bp->b_error = EROFS; + goto bad; + } +#endif + + /* beyond partition? */ + if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { + /* if exactly at end of disk, return an EOF */ + if (bp->b_blkno == maxsz) { + bp->b_resid = bp->b_bcount; + return (0); + } + /* or truncate if part of it fits */ + sz = maxsz - bp->b_blkno; + if (sz <= 0) { + bp->b_error = EINVAL; + goto bad; + } + bp->b_bcount = sz << DEV_BSHIFT; + } + + /* calculate cylinder for disksort to order transfers with */ + bp->b_pblkno = blkno + sp->ds_offset; + if (lp == NULL) + bp->b_cylinder = 0; /* XXX always 0 would be better */ + else + bp->b_cylinder = bp->b_pblkno / lp->d_secpercyl; + + /* + * Snoop on label accesses if the slice offset is nonzero. Fudge + * offsets in the label to keep the in-core label coherent with + * the on-disk one. + */ + if (blkno <= LABELSECTOR + labelsect +#if LABELSECTOR != 0 + && bp->b_blkno + sz > LABELSECTOR + labelsect +#endif + && sp->ds_offset != 0) { + struct iodone_chain *ic; + + ic = malloc(sizeof *ic , M_DEVBUF, M_WAITOK); + ic->ic_prev_flags = bp->b_flags; + ic->ic_prev_iodone = bp->b_iodone; + ic->ic_prev_iodone_chain = bp->b_iodone_chain; + ic->ic_args[0].ia_long = (LABELSECTOR + labelsect - blkno) + << DEV_BSHIFT; + ic->ic_args[1].ia_ptr = sp; + bp->b_flags |= B_CALL; + bp->b_iodone = dsiodone; + bp->b_iodone_chain = ic; + if (!(bp->b_flags & B_READ)) { + /* + * XXX even disklabel(8) writes directly so we need + * to adjust writes. Perhaps we should drop support + * for DIOCWLABEL (always write protect labels) and + * require the use of DIOCWDINFO. + * + * XXX probably need to copy the data to avoid even + * temporarily corrupting the in-core copy. + */ + if (bp->b_vp != NULL) + bp->b_vp->v_numoutput++; + msg = fixlabel((char *)NULL, sp, + (struct disklabel *) + (bp->b_data + ic->ic_args[0].ia_long), + TRUE); + if (msg != NULL) { + printf("%s\n", msg); + bp->b_error = EROFS; + goto bad; + } + } + } + return (1); + +bad: + bp->b_flags |= B_ERROR; + return (-1); +} + +void +dsclose(dev, mode, ssp) + dev_t dev; + int mode; + struct diskslices *ssp; +{ + u_char mask; + struct diskslice *sp; + + sp = &ssp->dss_slices[dkslice(dev)]; + mask = 1 << dkpart(dev); + switch (mode) { + case S_IFBLK: + sp->ds_bopenmask &= ~mask; + break; + case S_IFCHR: + sp->ds_copenmask &= ~mask; + break; + } + sp->ds_openmask = sp->ds_bopenmask | sp->ds_copenmask; +} + +void +dsgone(sspp) + struct diskslices **sspp; +{ + int slice; + struct diskslice *sp; + struct diskslices *ssp; + + for (slice = 0, ssp = *sspp; slice < ssp->dss_nslices; slice++) { + sp = &ssp->dss_slices[slice]; + if (sp->ds_bad != NULL) { + free(sp->ds_bad, M_DEVBUF); + set_ds_bad(ssp, slice, (struct dkbad_intern *)NULL); + } + if (sp->ds_label != NULL) { + free(sp->ds_label, M_DEVBUF); + set_ds_label(ssp, slice, (struct disklabel *)NULL); + } + } + free(ssp, M_DEVBUF); + *sspp = NULL; +} + +/* + * For the "write" commands (DIOCSBAD, DIOCSDINFO and DIOCWDINFO), this + * is subject to the same restriction as dsopen(). + */ +int +dsioctl(dname, dev, cmd, data, flags, sspp, strat, setgeom) + char *dname; + dev_t dev; + int cmd; + caddr_t data; + int flags; + struct diskslices **sspp; + d_strategy_t *strat; + ds_setgeom_t *setgeom; +{ + int error; + struct disklabel *lp; + int old_wlabel; + int slice; + struct diskslice *sp; + struct diskslices *ssp; + + slice = dkslice(dev); + ssp = *sspp; + sp = &ssp->dss_slices[slice]; + lp = sp->ds_label; + switch (cmd) { + + case DIOCGDINFO: + if (lp == NULL) + return (EINVAL); + *(struct disklabel *)data = *lp; + return (0); + +#ifdef notyet + case DIOCGDINFOP: + if (lp == NULL) + return (EINVAL); + *(struct disklabel **)data = lp; + return (0); +#endif + + case DIOCGPART: + if (lp == NULL) + return (EINVAL); + ((struct partinfo *)data)->disklab = lp; + ((struct partinfo *)data)->part + = &lp->d_partitions[dkpart(dev)]; + return (0); + + case DIOCGSLICEINFO: + *(struct diskslices *)data = *ssp; + return (0); + + case DIOCSBAD: + if (slice == WHOLE_DISK_SLICE) + return (ENODEV); + if (!(flags & FWRITE)) + return (EBADF); + if (lp == NULL) + return (EINVAL); + if (sp->ds_bad != NULL) + free(sp->ds_bad, M_DEVBUF); + set_ds_bad(ssp, slice, internbad144((struct dkbad *)data, lp)); + return (0); + + case DIOCSDINFO: + if (slice == WHOLE_DISK_SLICE) + return (ENODEV); + if (!(flags & FWRITE)) + return (EBADF); + lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK); + if (sp->ds_label == NULL) + bzero(lp, sizeof *lp); + else + bcopy(sp->ds_label, lp, sizeof *lp); + error = setdisklabel(lp, (struct disklabel *)data, + sp->ds_label != NULL + ? sp->ds_openmask : (u_long)0); + /* XXX why doesn't setdisklabel() check this? */ + if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0) + error = EINVAL; +#if 0 /* XXX */ + if (error != 0 && setgeom != NULL) + error = setgeom(lp); +#endif + if (error != 0) { + free(lp, M_DEVBUF); + return (error); + } + if (sp->ds_label != NULL) + free(sp->ds_label, M_DEVBUF); + set_ds_label(ssp, slice, lp); + return (0); + + case DIOCSYNCSLICEINFO: + if (slice != WHOLE_DISK_SLICE || dkpart(dev) != RAW_PART) + return (EINVAL); + if (!*(int *)data) + for (slice = 0; slice < ssp->dss_nslices; slice++) { + u_char openmask; + + openmask = ssp->dss_slices[slice].ds_openmask; + if (openmask + && (slice != WHOLE_DISK_SLICE + || openmask & ~(1 << RAW_PART))) + return (EBUSY); + } + + /* + * Temporarily forget the current slices struct and read + * the current one. + * XXX should wait for current accesses on this disk to + * complete, then lock out future accesses and opens. + */ + *sspp = NULL; + lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK); + *lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label; + error = dsopen(dname, dev, + ssp->dss_slices[WHOLE_DISK_SLICE].ds_copenmask + & (1 << RAW_PART) ? S_IFCHR : S_IFBLK, + sspp, lp, strat, setgeom); + if (error != 0) { + free(lp, M_DEVBUF); + *sspp = ssp; + return (error); + } + + /* + * Reopen everything. This is a no-op except in the "force" + * case and when the raw bdev and cdev are both open. Abort + * if anything fails. + */ + for (slice = 0; slice < ssp->dss_nslices; slice++) { + u_char openmask; + int part; + + for (openmask = ssp->dss_slices[slice].ds_bopenmask, + part = 0; openmask; openmask >>= 1, part++) { + if (!(openmask & 1)) + continue; + error = dsopen(dname, + dkmodslice(dkmodpart(dev, part), + slice), + S_IFBLK, sspp, lp, strat, + setgeom); + if (error != 0) { + free(lp, M_DEVBUF); + *sspp = ssp; + return (EBUSY); + } + } + for (openmask = ssp->dss_slices[slice].ds_copenmask, + part = 0; openmask; openmask >>= 1, part++) { + if (!(openmask & 1)) + continue; + error = dsopen(dname, + dkmodslice(dkmodpart(dev, part), + slice), + S_IFCHR, sspp, lp, strat, + setgeom); + if (error != 0) { + free(lp, M_DEVBUF); + *sspp = ssp; + return (EBUSY); + } + } + } + + free(lp, M_DEVBUF); + dsgone(&ssp); + return (0); + + case DIOCWDINFO: + error = dsioctl(dname, dev, DIOCSDINFO, data, flags, &ssp, + strat, setgeom); + if (error != 0) + return (error); + /* + * XXX this used to hack on dk_openpart to fake opening + * partition 0 in case that is used instead of dkpart(dev). + */ + old_wlabel = sp->ds_wlabel; + set_ds_wlabel(ssp, slice, TRUE); + error = writedisklabel(dev, strat, sp->ds_label); + /* XXX should invalidate in-core label if write failed. */ + set_ds_wlabel(ssp, slice, old_wlabel); + return (error); + + case DIOCWLABEL: + if (slice == WHOLE_DISK_SLICE) + return (ENODEV); + if (!(flags & FWRITE)) + return (EBADF); + set_ds_wlabel(ssp, slice, *(int *)data != 0); + return (0); + + default: + return (-1); + } +} + +static void +dsiodone(bp) + struct buf *bp; +{ + struct iodone_chain *ic; + char *msg; + + ic = bp->b_iodone_chain; + bp->b_flags = (ic->ic_prev_flags & B_CALL) + | (bp->b_flags & ~(B_CALL | B_DONE)); + bp->b_iodone = ic->ic_prev_iodone; + bp->b_iodone_chain = ic->ic_prev_iodone_chain; + if (!(bp->b_flags & B_READ) + || (!(bp->b_flags & B_ERROR) && bp->b_error == 0)) { + msg = fixlabel((char *)NULL, ic->ic_args[1].ia_ptr, + (struct disklabel *) + (bp->b_data + ic->ic_args[0].ia_long), + FALSE); + if (msg != NULL) + printf("%s\n", msg); + } + free(ic, M_DEVBUF); + biodone(bp); +} + +int +dsisopen(ssp) + struct diskslices *ssp; +{ + int slice; + + if (ssp == NULL) + return (0); + for (slice = 0; slice < ssp->dss_nslices; slice++) + if (ssp->dss_slices[slice].ds_openmask) + return (1); + return (0); +} + +char * +dsname(dname, unit, slice, part, partname) + char *dname; + int unit; + int slice; + int part; + char *partname; +{ + static char name[32]; + + if (strlen(dname) > 16) + dname = "nametoolong"; + sprintf(name, "%s%d", dname, unit); + partname[0] = '\0'; + if (slice != WHOLE_DISK_SLICE || part != RAW_PART) { + partname[0] = 'a' + part; + partname[1] = '\0'; + if (slice != COMPATIBILITY_SLICE) + sprintf(name + strlen(name), "s%d", slice - 1); + } + return (name); +} + +/* + * This should only be called when the unit is inactive and the strategy + * routine should not allow it to become active unless we call it. Our + * strategy routine must be special to allow activity. + */ +int +dsopen(dname, dev, mode, sspp, lp, strat, setgeom) + char *dname; + dev_t dev; + int mode; + struct diskslices **sspp; + struct disklabel *lp; + d_strategy_t *strat; + ds_setgeom_t *setgeom; +{ + int error; + struct disklabel *lp1; + char *msg; + u_char mask; + bool_t need_init; + int part; + char partname[2]; + int slice; + char *sname; + struct diskslice *sp; + struct diskslices *ssp; + int unit; + + /* + * XXX reinitialize the slice table unless there is an open device + * on the unit. This should only be done if the media has changed. + */ + ssp = *sspp; + need_init = !dsisopen(ssp); + if (ssp != NULL && need_init) + dsgone(sspp); + if (need_init) { + TRACE(("dsinit\n")); + error = dsinit(dname, dev, strat, lp, sspp); + if (error != 0) { + dsgone(sspp); + return (error); + } + lp->d_npartitions = RAW_PART + 1; + lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; + ssp = *sspp; + + /* + * If there are no real slices, then make the compatiblity + * slice cover the whole disk. + */ + if (ssp->dss_nslices == BASE_SLICE) + ssp->dss_slices[COMPATIBILITY_SLICE].ds_size + = lp->d_secperunit; + + /* Point the compatibility slice at the BSD slice, if any. */ + for (slice = BASE_SLICE, sp = &ssp->dss_slices[BASE_SLICE]; + slice < ssp->dss_nslices; slice++, sp++) + if (sp->ds_type == DOSPTYP_386BSD /* XXX */) { + ssp->dss_first_bsd_slice = slice; + ssp->dss_slices[COMPATIBILITY_SLICE].ds_offset + = sp->ds_offset; + ssp->dss_slices[COMPATIBILITY_SLICE].ds_size + = sp->ds_size; + ssp->dss_slices[COMPATIBILITY_SLICE].ds_type + = sp->ds_type; + break; + } + + lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK); + *lp1 = *lp; + ssp->dss_slices[WHOLE_DISK_SLICE].ds_label = lp1; + ssp->dss_slices[WHOLE_DISK_SLICE].ds_wlabel = TRUE; + if (setgeom != NULL) { + error = setgeom(lp); + if (error != 0) { + dsgone(sspp); + return (error); + } + } + } + + slice = dkslice(dev); + if (slice >= ssp->dss_nslices) + return (ENXIO); + sp = &ssp->dss_slices[slice]; + part = dkpart(dev); + unit = dkunit(dev); + if (sp->ds_label == NULL) { + set_ds_wlabel(ssp, slice, TRUE); /* XXX invert */ + lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK); + *lp1 = *lp; + lp = lp1; + TRACE(("readdisklabel\n")); + msg = readdisklabel(dkmodpart(dev, RAW_PART), strat, lp); +#if 0 /* XXX */ + if (msg == NULL && setgeom != NULL && setgeom(lp) != 0) + msg = "setgeom failed"; +#endif + sname = dsname(dname, unit, slice, RAW_PART, partname); + if (msg == NULL) + msg = fixlabel(sname, sp, lp, FALSE); + if (msg != NULL) { + free(lp, M_DEVBUF); + if (sp->ds_type == DOSPTYP_386BSD /* XXX */) + log(LOG_WARNING, "%s: cannot find label (%s)\n", + sname, msg); + if (part == RAW_PART) + goto out; + return (EINVAL); /* XXX needs translation */ + } + if (lp->d_flags & D_BADSECT) { + struct dkbad *btp; + + btp = malloc(sizeof *btp, M_DEVBUF, M_WAITOK); + TRACE(("readbad144\n")); + msg = readbad144(dev, strat, lp, btp); + if (msg != NULL) { + log(LOG_WARNING, + "%s: cannot find bad sector table (%s)\n", + sname, msg); + free(btp, M_DEVBUF); + free(lp, M_DEVBUF); + if (part == RAW_PART) + goto out; + return (EINVAL); /* XXX needs translation */ + } + set_ds_bad(ssp, slice, internbad144(btp, lp)); + free(btp, M_DEVBUF); + if (sp->ds_bad == NULL) { + free(lp, M_DEVBUF); + if (part == RAW_PART) + goto out; + return (EINVAL); /* XXX needs translation */ + } + } + set_ds_label(ssp, slice, lp); + set_ds_wlabel(ssp, slice, FALSE); + } + if (part != RAW_PART + && (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions)) + return (EINVAL); /* XXX needs translation */ +out: + mask = 1 << part; + switch (mode) { + case S_IFBLK: + sp->ds_bopenmask |= mask; + break; + case S_IFCHR: + sp->ds_copenmask |= mask; + break; + } + sp->ds_openmask = sp->ds_bopenmask | sp->ds_copenmask; + return (0); +} + +int +dssize(dev, sspp, dopen, dclose) + dev_t dev; + struct diskslices **sspp; + d_open_t dopen; + d_close_t dclose; +{ + struct disklabel *lp; + int part; + int slice; + struct diskslices *ssp; + + slice = dkslice(dev); + part = dkpart(dev); + ssp = *sspp; + if (ssp == NULL || slice >= ssp->dss_nslices + || !(ssp->dss_slices[slice].ds_bopenmask & (1 << part))) { + if (dopen(dev, FREAD, S_IFBLK, (struct proc *)NULL) != 0) + return (-1); + dclose(dev, FREAD, S_IFBLK, (struct proc *)NULL); + ssp = *sspp; + } + lp = ssp->dss_slices[slice].ds_label; + if (lp == NULL) + return (-1); + return ((int)lp->d_partitions[part].p_size); +} + +static char * +fixlabel(sname, sp, lp, writeflag) + char *sname; + struct diskslice *sp; + struct disklabel *lp; + int writeflag; +{ + u_long end; + u_long offset; + int part; + struct partition *pp; + u_long start; + bool_t warned; + + /* These errors "can't happen" so don't bother reporting details. */ + if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) + return ("fixlabel: invalid magic"); + if (dkcksum(lp) != 0) + return ("fixlabel: invalid checksum"); + + pp = &lp->d_partitions[RAW_PART]; + if (writeflag) { + start = 0; + offset = sp->ds_offset; + } else { + start = sp->ds_offset; + offset = -sp->ds_offset; + } + if (pp->p_offset != start) { + if (sname != NULL) { + printf( +"%s: rejecting BSD label: raw partition offset != slice offset\n", + sname); + slice_info(sname, sp); + partition_info(sname, RAW_PART, pp); + } + return ("fixlabel: raw partition offset != slice offset"); + } + if (pp->p_size != sp->ds_size) { + if (sname != NULL) { + printf("%s: raw partition size != slice size\n", sname); + slice_info(sname, sp); + partition_info(sname, RAW_PART, pp); + } + if (pp->p_size > sp->ds_size) { + if (sname == NULL) + return ("fixlabel: raw partition size > slice size"); + printf("%s: truncating raw partition\n", sname); + pp->p_size = sp->ds_size; + } + } + end = start + sp->ds_size; + if (start > end) + return ("fixlabel: slice wraps"); + if (lp->d_secpercyl <= 0) + return ("fixlabel: d_secpercyl <= 0"); + pp -= RAW_PART; + warned = FALSE; + for (part = 0; part < lp->d_npartitions; part++, pp++) { + if (pp->p_offset != 0 || pp->p_size != 0) { + if (pp->p_offset < start + || pp->p_offset + pp->p_size > end + || pp->p_offset + pp->p_size < pp->p_offset) { + if (sname != NULL) { + printf( +"%s: rejecting partition in BSD label: it isn't entirely within the slice\n", + sname); + if (!warned) { + slice_info(sname, sp); + warned = TRUE; + } + partition_info(sname, part, pp); + } + /* XXX else silently discard junk. */ + bzero(pp, sizeof *pp); + } else + pp->p_offset += offset; + } + } + lp->d_ncylinders = sp->ds_size / lp->d_secpercyl; + lp->d_secperunit = sp->ds_size; + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + return (NULL); +} + +static void +partition_info(sname, part, pp) + char *sname; + int part; + struct partition *pp; +{ + printf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part, + pp->p_offset, pp->p_offset + pp->p_size - 1, pp->p_size); +} + +static void +slice_info(sname, sp) + char *sname; + struct diskslice *sp; +{ + printf("%s: start %lu, end %lu, size %lu\n", sname, + sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size); +} + +/* + * Most changes to ds_bad, ds_label and ds_wlabel are made using the + * following functions to ensure coherency of the compatibility slice + * with the first BSD slice. The openmask fields are _not_ shared and + * the other fields (ds_offset and ds_size) aren't changed after they + * are initialized. + */ +static void +set_ds_bad(ssp, slice, btp) + struct diskslices *ssp; + int slice; + struct dkbad_intern *btp; +{ + ssp->dss_slices[slice].ds_bad = btp; + if (slice == COMPATIBILITY_SLICE) + ssp->dss_slices[ssp->dss_first_bsd_slice].ds_bad = btp; + else if (slice == ssp->dss_first_bsd_slice) + ssp->dss_slices[COMPATIBILITY_SLICE].ds_bad = btp; +} + +static void +set_ds_label(ssp, slice, lp) + struct diskslices *ssp; + int slice; + struct disklabel *lp; +{ + ssp->dss_slices[slice].ds_label = lp; + if (slice == COMPATIBILITY_SLICE) + ssp->dss_slices[ssp->dss_first_bsd_slice].ds_label = lp; + else if (slice == ssp->dss_first_bsd_slice) + ssp->dss_slices[COMPATIBILITY_SLICE].ds_label = lp; +} + +static void +set_ds_wlabel(ssp, slice, wlabel) + struct diskslices *ssp; + int slice; + int wlabel; +{ + ssp->dss_slices[slice].ds_wlabel = wlabel; + if (slice == COMPATIBILITY_SLICE) + ssp->dss_slices[ssp->dss_first_bsd_slice].ds_wlabel = wlabel; + else if (slice == ssp->dss_first_bsd_slice) + ssp->dss_slices[COMPATIBILITY_SLICE].ds_wlabel = wlabel; +} |