1994-12-12 00:20:34 +00:00
|
|
|
/*-
|
|
|
|
* 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 $
|
1999-08-28 01:08:13 +00:00
|
|
|
* $FreeBSD$
|
1994-12-12 00:20:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
Divorce "dev_t" from the "major|minor" bitmap, which is now called
udev_t in the kernel but still called dev_t in userland.
Provide functions to manipulate both types:
major() umajor()
minor() uminor()
makedev() umakedev()
dev2udev() udev2dev()
For now they're functions, they will become in-line functions
after one of the next two steps in this process.
Return major/minor/makedev to macro-hood for userland.
Register a name in cdevsw[] for the "filedescriptor" driver.
In the kernel the udev_t appears in places where we have the
major/minor number combination, (ie: a potential device: we
may not have the driver nor the device), like in inodes, vattr,
cdevsw registration and so on, whereas the dev_t appears where
we carry around a reference to a actual device.
In the future the cdevsw and the aliased-from vnode will be hung
directly from the dev_t, along with up to two softc pointers for
the device driver and a few houskeeping bits. This will essentially
replace the current "alias" check code (same buck, bigger bang).
A little stunt has been provided to try to catch places where the
wrong type is being used (dev_t vs udev_t), if you see something
not working, #undef DEVT_FASCIST in kern/kern_conf.c and see if
it makes a difference. If it does, please try to track it down
(many hands make light work) or at least try to reproduce it
as simply as possible, and describe how to do that.
Without DEVT_FASCIST I belive this patch is a no-op.
Stylistic/posixoid comments about the userland view of the <sys/*.h>
files welcome now, from userland they now contain the end result.
Next planned step: make all dev_t's refer to the same devsw[] which
means convert BLK's to CHR's at the perimeter of the vnodes and
other places where they enter the game (bootdev, mknod, sysctl).
1999-05-11 19:55:07 +00:00
|
|
|
#include <sys/systm.h>
|
2000-05-05 09:59:14 +00:00
|
|
|
#include <sys/bio.h>
|
1996-09-20 17:39:44 +00:00
|
|
|
#include <sys/conf.h>
|
2002-04-08 09:20:07 +00:00
|
|
|
#include <sys/disk.h>
|
1994-12-12 00:20:34 +00:00
|
|
|
#include <sys/disklabel.h>
|
|
|
|
#include <sys/diskslice.h>
|
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/stat.h>
|
2002-06-06 00:35:07 +00:00
|
|
|
#include <sys/stdint.h>
|
1994-12-12 00:20:34 +00:00
|
|
|
#include <sys/syslog.h>
|
1995-05-24 23:33:42 +00:00
|
|
|
#include <sys/vnode.h>
|
1994-12-12 00:20:34 +00:00
|
|
|
|
1995-03-04 11:42:27 +00:00
|
|
|
#define TRACE(str) do { if (ds_debug) printf str; } while (0)
|
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
typedef u_char bool_t;
|
|
|
|
|
1995-03-04 11:42:27 +00:00
|
|
|
static volatile bool_t ds_debug;
|
|
|
|
|
2002-03-19 21:25:46 +00:00
|
|
|
static struct disklabel *clone_label(struct disklabel *lp);
|
|
|
|
static void dsiodone(struct bio *bp);
|
|
|
|
static char *fixlabel(char *sname, struct diskslice *sp,
|
|
|
|
struct disklabel *lp, int writeflag);
|
|
|
|
static void free_ds_label(struct diskslices *ssp, int slice);
|
|
|
|
static void partition_info(char *sname, int part, struct partition *pp);
|
|
|
|
static void slice_info(char *sname, struct diskslice *sp);
|
|
|
|
static void set_ds_label(struct diskslices *ssp, int slice,
|
|
|
|
struct disklabel *lp);
|
|
|
|
static void set_ds_labeldevs(dev_t dev, struct diskslices *ssp);
|
|
|
|
static void set_ds_wlabel(struct diskslices *ssp, int slice,
|
|
|
|
int wlabel);
|
1994-12-12 00:20:34 +00:00
|
|
|
|
1998-07-20 14:35:27 +00:00
|
|
|
/*
|
|
|
|
* Duplicate a label for the whole disk, and initialize defaults in the
|
|
|
|
* copy for fields that are not already initialized. The caller only
|
|
|
|
* needs to initialize d_secsize and d_secperunit, and zero the fields
|
|
|
|
* that are to be defaulted.
|
|
|
|
*/
|
|
|
|
static struct disklabel *
|
|
|
|
clone_label(lp)
|
|
|
|
struct disklabel *lp;
|
|
|
|
{
|
|
|
|
struct disklabel *lp1;
|
|
|
|
|
|
|
|
lp1 = malloc(sizeof *lp1, M_DEVBUF, M_WAITOK);
|
|
|
|
*lp1 = *lp;
|
|
|
|
lp = NULL;
|
|
|
|
if (lp1->d_typename[0] == '\0')
|
|
|
|
strncpy(lp1->d_typename, "amnesiac", sizeof(lp1->d_typename));
|
|
|
|
if (lp1->d_packname[0] == '\0')
|
|
|
|
strncpy(lp1->d_packname, "fictitious", sizeof(lp1->d_packname));
|
|
|
|
if (lp1->d_nsectors == 0)
|
|
|
|
lp1->d_nsectors = 32;
|
|
|
|
if (lp1->d_ntracks == 0)
|
|
|
|
lp1->d_ntracks = 64;
|
|
|
|
lp1->d_secpercyl = lp1->d_nsectors * lp1->d_ntracks;
|
|
|
|
lp1->d_ncylinders = lp1->d_secperunit / lp1->d_secpercyl;
|
|
|
|
if (lp1->d_rpm == 0)
|
|
|
|
lp1->d_rpm = 3600;
|
|
|
|
if (lp1->d_interleave == 0)
|
|
|
|
lp1->d_interleave = 1;
|
|
|
|
if (lp1->d_npartitions < RAW_PART + 1)
|
|
|
|
lp1->d_npartitions = MAXPARTITIONS;
|
|
|
|
if (lp1->d_bbsize == 0)
|
|
|
|
lp1->d_bbsize = BBSIZE;
|
|
|
|
lp1->d_partitions[RAW_PART].p_size = lp1->d_secperunit;
|
|
|
|
lp1->d_magic = DISKMAGIC;
|
|
|
|
lp1->d_magic2 = DISKMAGIC;
|
|
|
|
lp1->d_checksum = dkcksum(lp1);
|
|
|
|
return (lp1);
|
|
|
|
}
|
|
|
|
|
2002-01-17 18:33:18 +00:00
|
|
|
dev_t
|
|
|
|
dkmodpart(dev_t dev, int part)
|
|
|
|
{
|
|
|
|
return (makedev(major(dev), (minor(dev) & ~7) | part));
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_t
|
|
|
|
dkmodslice(dev_t dev, int slice)
|
|
|
|
{
|
|
|
|
return (makedev(major(dev), (minor(dev) & ~0x1f0000) | (slice << 16)));
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int
|
|
|
|
dkunit(dev_t dev)
|
|
|
|
{
|
|
|
|
return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f));
|
|
|
|
}
|
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
/*
|
|
|
|
* 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 Split buffers that are too big for the device.
|
|
|
|
* o Check for overflow.
|
|
|
|
* o Finish cleaning this up.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
dscheck(bp, ssp)
|
2000-04-15 05:54:02 +00:00
|
|
|
struct bio *bp;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct diskslices *ssp;
|
|
|
|
{
|
2002-06-21 06:18:05 +00:00
|
|
|
daddr_t blkno;
|
|
|
|
daddr_t endsecno;
|
|
|
|
daddr_t labelsect;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct disklabel *lp;
|
1995-02-22 21:51:53 +00:00
|
|
|
char *msg;
|
1998-07-29 11:15:54 +00:00
|
|
|
long nsec;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct partition *pp;
|
2002-06-21 06:18:05 +00:00
|
|
|
daddr_t secno;
|
|
|
|
daddr_t slicerel_secno;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct diskslice *sp;
|
|
|
|
|
2000-04-15 05:54:02 +00:00
|
|
|
blkno = bp->bio_blkno;
|
1998-07-29 11:15:54 +00:00
|
|
|
if (blkno < 0) {
|
2000-04-15 05:54:02 +00:00
|
|
|
printf("dscheck(%s): negative bio_blkno %ld\n",
|
|
|
|
devtoname(bp->bio_dev), (long)blkno);
|
|
|
|
bp->bio_error = EINVAL;
|
1996-01-07 22:39:06 +00:00
|
|
|
goto bad;
|
1996-01-16 18:11:24 +00:00
|
|
|
}
|
2000-04-15 05:54:02 +00:00
|
|
|
sp = &ssp->dss_slices[dkslice(bp->bio_dev)];
|
1994-12-12 00:20:34 +00:00
|
|
|
lp = sp->ds_label;
|
1998-07-29 11:15:54 +00:00
|
|
|
if (ssp->dss_secmult == 1) {
|
2000-04-15 05:54:02 +00:00
|
|
|
if (bp->bio_bcount % (u_long)DEV_BSIZE)
|
1998-07-29 11:15:54 +00:00
|
|
|
goto bad_bcount;
|
|
|
|
secno = blkno;
|
2000-04-15 05:54:02 +00:00
|
|
|
nsec = bp->bio_bcount >> DEV_BSHIFT;
|
1998-07-29 11:15:54 +00:00
|
|
|
} else if (ssp->dss_secshift != -1) {
|
2000-04-15 05:54:02 +00:00
|
|
|
if (bp->bio_bcount & (ssp->dss_secsize - 1))
|
1998-07-29 11:15:54 +00:00
|
|
|
goto bad_bcount;
|
|
|
|
if (blkno & (ssp->dss_secmult - 1))
|
|
|
|
goto bad_blkno;
|
|
|
|
secno = blkno >> ssp->dss_secshift;
|
2000-04-15 05:54:02 +00:00
|
|
|
nsec = bp->bio_bcount >> (DEV_BSHIFT + ssp->dss_secshift);
|
1998-07-29 11:15:54 +00:00
|
|
|
} else {
|
2000-04-15 05:54:02 +00:00
|
|
|
if (bp->bio_bcount % ssp->dss_secsize)
|
1998-07-29 11:15:54 +00:00
|
|
|
goto bad_bcount;
|
|
|
|
if (blkno % ssp->dss_secmult)
|
|
|
|
goto bad_blkno;
|
|
|
|
secno = blkno / ssp->dss_secmult;
|
2000-04-15 05:54:02 +00:00
|
|
|
nsec = bp->bio_bcount / ssp->dss_secsize;
|
1998-07-29 11:15:54 +00:00
|
|
|
}
|
1994-12-12 00:20:34 +00:00
|
|
|
if (lp == NULL) {
|
|
|
|
labelsect = -LABELSECTOR - 1;
|
1998-07-29 11:15:54 +00:00
|
|
|
endsecno = sp->ds_size;
|
|
|
|
slicerel_secno = secno;
|
1994-12-12 00:20:34 +00:00
|
|
|
} else {
|
|
|
|
labelsect = lp->d_partitions[LABEL_PART].p_offset;
|
1995-02-16 15:19:19 +00:00
|
|
|
if (labelsect != 0) Debugger("labelsect != 0 in dscheck()");
|
2000-04-15 05:54:02 +00:00
|
|
|
pp = &lp->d_partitions[dkpart(bp->bio_dev)];
|
1998-07-29 11:15:54 +00:00
|
|
|
endsecno = pp->p_size;
|
|
|
|
slicerel_secno = pp->p_offset + secno;
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* overwriting disk label ? */
|
|
|
|
/* XXX should also protect bootstrap in first 8K */
|
1998-07-29 11:15:54 +00:00
|
|
|
if (slicerel_secno <= LABELSECTOR + labelsect &&
|
1994-12-12 00:20:34 +00:00
|
|
|
#if LABELSECTOR != 0
|
1998-07-29 11:15:54 +00:00
|
|
|
slicerel_secno + nsec > LABELSECTOR + labelsect &&
|
1994-12-12 00:20:34 +00:00
|
|
|
#endif
|
2000-04-15 05:54:02 +00:00
|
|
|
(bp->bio_cmd == BIO_WRITE) && sp->ds_wlabel == 0) {
|
|
|
|
bp->bio_error = EROFS;
|
1994-12-12 00:20:34 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(DOSBBSECTOR) && defined(notyet)
|
|
|
|
/* overwriting master boot record? */
|
2000-04-15 05:54:02 +00:00
|
|
|
if (slicerel_secno <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) &&
|
1994-12-12 00:20:34 +00:00
|
|
|
sp->ds_wlabel == 0) {
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_error = EROFS;
|
1994-12-12 00:20:34 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* beyond partition? */
|
2002-06-06 00:35:07 +00:00
|
|
|
if ((uintmax_t)secno + nsec > endsecno) {
|
1994-12-12 00:20:34 +00:00
|
|
|
/* if exactly at end of disk, return an EOF */
|
1998-07-29 11:15:54 +00:00
|
|
|
if (secno == endsecno) {
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_resid = bp->bio_bcount;
|
1994-12-12 00:20:34 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
/* or truncate if part of it fits */
|
2002-06-06 00:35:07 +00:00
|
|
|
if (secno > endsecno) {
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_error = EINVAL;
|
1994-12-12 00:20:34 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2002-06-06 00:35:07 +00:00
|
|
|
bp->bio_bcount = (endsecno - secno) * ssp->dss_secsize;
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
|
|
|
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_pblkno = sp->ds_offset + slicerel_secno;
|
1995-02-18 22:10:44 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
1998-07-29 11:15:54 +00:00
|
|
|
if (slicerel_secno <= LABELSECTOR + labelsect
|
1995-02-18 22:10:44 +00:00
|
|
|
#if LABELSECTOR != 0
|
1998-07-29 11:15:54 +00:00
|
|
|
&& slicerel_secno + nsec > LABELSECTOR + labelsect
|
1995-02-18 22:10:44 +00:00
|
|
|
#endif
|
|
|
|
&& sp->ds_offset != 0) {
|
|
|
|
struct iodone_chain *ic;
|
|
|
|
|
|
|
|
ic = malloc(sizeof *ic , M_DEVBUF, M_WAITOK);
|
2000-04-15 05:54:02 +00:00
|
|
|
ic->ic_prev_flags = bp->bio_flags;
|
|
|
|
ic->ic_prev_iodone = bp->bio_done;
|
|
|
|
ic->ic_prev_iodone_chain = bp->bio_done_chain;
|
1998-07-29 11:15:54 +00:00
|
|
|
ic->ic_args[0].ia_long = (LABELSECTOR + labelsect -
|
|
|
|
slicerel_secno) * ssp->dss_secsize;
|
1995-02-22 21:51:53 +00:00
|
|
|
ic->ic_args[1].ia_ptr = sp;
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_done = dsiodone;
|
|
|
|
bp->bio_done_chain = ic;
|
|
|
|
if (!(bp->bio_cmd == BIO_READ)) {
|
1995-02-18 22:10:44 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
1998-07-29 11:15:54 +00:00
|
|
|
/* XXX need name here. */
|
1995-02-22 21:51:53 +00:00
|
|
|
msg = fixlabel((char *)NULL, sp,
|
|
|
|
(struct disklabel *)
|
2000-04-15 05:54:02 +00:00
|
|
|
(bp->bio_data + ic->ic_args[0].ia_long),
|
1995-02-22 21:51:53 +00:00
|
|
|
TRUE);
|
|
|
|
if (msg != NULL) {
|
1999-08-31 18:36:15 +00:00
|
|
|
printf("dscheck(%s): %s\n",
|
2000-04-15 05:54:02 +00:00
|
|
|
devtoname(bp->bio_dev), msg);
|
|
|
|
bp->bio_error = EROFS;
|
1995-02-22 21:51:53 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
1995-02-18 22:10:44 +00:00
|
|
|
}
|
|
|
|
}
|
1994-12-12 00:20:34 +00:00
|
|
|
return (1);
|
|
|
|
|
1998-07-29 11:15:54 +00:00
|
|
|
bad_bcount:
|
1999-09-01 09:39:11 +00:00
|
|
|
printf(
|
2000-04-15 05:54:02 +00:00
|
|
|
"dscheck(%s): bio_bcount %ld is not on a sector boundary (ssize %d)\n",
|
|
|
|
devtoname(bp->bio_dev), bp->bio_bcount, ssp->dss_secsize);
|
|
|
|
bp->bio_error = EINVAL;
|
1998-07-29 11:15:54 +00:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
bad_blkno:
|
1999-09-01 09:39:11 +00:00
|
|
|
printf(
|
2000-04-15 05:54:02 +00:00
|
|
|
"dscheck(%s): bio_blkno %ld is not on a sector boundary (ssize %d)\n",
|
|
|
|
devtoname(bp->bio_dev), (long)blkno, ssp->dss_secsize);
|
|
|
|
bp->bio_error = EINVAL;
|
1998-07-29 11:15:54 +00:00
|
|
|
goto bad;
|
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
bad:
|
2000-04-15 05:54:02 +00:00
|
|
|
bp->bio_resid = bp->bio_bcount;
|
|
|
|
bp->bio_flags |= BIO_ERROR;
|
1994-12-12 00:20:34 +00:00
|
|
|
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);
|
2000-01-16 09:25:34 +00:00
|
|
|
sp->ds_openmask &= ~mask;
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
|
|
|
|
1994-12-16 16:14:39 +00:00
|
|
|
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];
|
1996-04-19 19:22:29 +00:00
|
|
|
free_ds_label(ssp, slice);
|
1994-12-16 16:14:39 +00:00
|
|
|
}
|
1995-02-16 15:19:19 +00:00
|
|
|
free(ssp, M_DEVBUF);
|
1994-12-16 16:14:39 +00:00
|
|
|
*sspp = NULL;
|
|
|
|
}
|
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
/*
|
1999-12-08 09:33:00 +00:00
|
|
|
* For the "write" commands (DIOCSDINFO and DIOCWDINFO), this
|
1994-12-12 00:20:34 +00:00
|
|
|
* is subject to the same restriction as dsopen().
|
|
|
|
*/
|
|
|
|
int
|
1999-08-28 14:33:44 +00:00
|
|
|
dsioctl(dev, cmd, data, flags, sspp)
|
1994-12-12 00:20:34 +00:00
|
|
|
dev_t dev;
|
1998-08-13 08:09:08 +00:00
|
|
|
u_long cmd;
|
1994-12-12 00:20:34 +00:00
|
|
|
caddr_t data;
|
|
|
|
int flags;
|
1995-04-30 15:16:02 +00:00
|
|
|
struct diskslices **sspp;
|
1994-12-12 00:20:34 +00:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
struct disklabel *lp;
|
|
|
|
int old_wlabel;
|
1997-09-16 10:11:49 +00:00
|
|
|
u_char openmask;
|
|
|
|
int part;
|
1995-02-16 15:19:19 +00:00
|
|
|
int slice;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct diskslice *sp;
|
1995-04-30 15:16:02 +00:00
|
|
|
struct diskslices *ssp;
|
2000-10-31 07:05:40 +00:00
|
|
|
struct partition *pp;
|
1994-12-12 00:20:34 +00:00
|
|
|
|
1995-02-16 15:19:19 +00:00
|
|
|
slice = dkslice(dev);
|
1995-04-30 15:16:02 +00:00
|
|
|
ssp = *sspp;
|
1995-02-16 15:19:19 +00:00
|
|
|
sp = &ssp->dss_slices[slice];
|
1994-12-12 00:20:34 +00:00
|
|
|
lp = sp->ds_label;
|
|
|
|
switch (cmd) {
|
|
|
|
|
2002-07-23 14:30:27 +00:00
|
|
|
case DIOCGDINFO:
|
|
|
|
if (lp == NULL)
|
|
|
|
return (EINVAL);
|
|
|
|
*(struct disklabel *)data = *lp;
|
|
|
|
return (0);
|
|
|
|
|
2000-10-31 07:05:40 +00:00
|
|
|
case DIOCGDVIRGIN:
|
|
|
|
lp = (struct disklabel *)data;
|
|
|
|
if (ssp->dss_slices[WHOLE_DISK_SLICE].ds_label) {
|
|
|
|
*lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
|
|
|
|
} else {
|
|
|
|
bzero(lp, sizeof(struct disklabel));
|
|
|
|
}
|
|
|
|
|
|
|
|
lp->d_magic = DISKMAGIC;
|
|
|
|
lp->d_magic2 = DISKMAGIC;
|
|
|
|
pp = &lp->d_partitions[RAW_PART];
|
|
|
|
pp->p_offset = 0;
|
|
|
|
pp->p_size = sp->ds_size;
|
|
|
|
|
|
|
|
lp->d_npartitions = MAXPARTITIONS;
|
|
|
|
if (lp->d_interleave == 0)
|
|
|
|
lp->d_interleave = 1;
|
|
|
|
if (lp->d_rpm == 0)
|
|
|
|
lp->d_rpm = 3600;
|
|
|
|
if (lp->d_nsectors == 0)
|
|
|
|
lp->d_nsectors = 32;
|
|
|
|
if (lp->d_ntracks == 0)
|
|
|
|
lp->d_ntracks = 64;
|
|
|
|
|
|
|
|
lp->d_bbsize = BBSIZE;
|
2002-05-12 20:49:41 +00:00
|
|
|
lp->d_sbsize = 0;
|
2000-10-31 07:05:40 +00:00
|
|
|
lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
|
|
|
|
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 (0);
|
|
|
|
|
2002-07-23 14:30:27 +00:00
|
|
|
case DIOCGMEDIASIZE:
|
1994-12-12 00:20:34 +00:00
|
|
|
if (lp == NULL)
|
2002-07-23 14:30:27 +00:00
|
|
|
*(off_t *)data = (off_t)sp->ds_size * ssp->dss_secsize;
|
|
|
|
else
|
|
|
|
*(off_t *)data =
|
|
|
|
(off_t)lp->d_partitions[dkpart(dev)].p_size *
|
|
|
|
lp->d_secsize;
|
1994-12-12 00:20:34 +00:00
|
|
|
return (0);
|
|
|
|
|
2002-03-31 21:17:12 +00:00
|
|
|
case DIOCGSECTORSIZE:
|
2002-07-23 14:30:27 +00:00
|
|
|
*(u_int *)data = ssp->dss_secsize;
|
2002-03-31 21:17:12 +00:00
|
|
|
return (0);
|
|
|
|
|
1995-04-24 17:07:08 +00:00
|
|
|
case DIOCGSLICEINFO:
|
1998-06-06 03:06:55 +00:00
|
|
|
bcopy(ssp, data, (char *)&ssp->dss_slices[ssp->dss_nslices] -
|
|
|
|
(char *)ssp);
|
1995-04-24 17:07:08 +00:00
|
|
|
return (0);
|
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
case DIOCSDINFO:
|
1995-02-16 15:19:19 +00:00
|
|
|
if (slice == WHOLE_DISK_SLICE)
|
|
|
|
return (ENODEV);
|
1994-12-12 00:20:34 +00:00
|
|
|
if (!(flags & FWRITE))
|
|
|
|
return (EBADF);
|
|
|
|
lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
|
1995-02-22 21:51:53 +00:00
|
|
|
if (sp->ds_label == NULL)
|
|
|
|
bzero(lp, sizeof *lp);
|
|
|
|
else
|
|
|
|
bcopy(sp->ds_label, lp, sizeof *lp);
|
1998-02-15 05:41:31 +00:00
|
|
|
if (sp->ds_label == NULL)
|
|
|
|
openmask = 0;
|
|
|
|
else {
|
|
|
|
openmask = sp->ds_openmask;
|
|
|
|
if (slice == COMPATIBILITY_SLICE)
|
|
|
|
openmask |= ssp->dss_slices[
|
|
|
|
ssp->dss_first_bsd_slice].ds_openmask;
|
|
|
|
else if (slice == ssp->dss_first_bsd_slice)
|
|
|
|
openmask |= ssp->dss_slices[
|
|
|
|
COMPATIBILITY_SLICE].ds_openmask;
|
|
|
|
}
|
1994-12-12 00:20:34 +00:00
|
|
|
error = setdisklabel(lp, (struct disklabel *)data,
|
1998-02-15 05:41:31 +00:00
|
|
|
(u_long)openmask);
|
1995-02-18 22:10:44 +00:00
|
|
|
/* XXX why doesn't setdisklabel() check this? */
|
|
|
|
if (error == 0 && lp->d_partitions[RAW_PART].p_offset != 0)
|
1998-10-17 09:46:42 +00:00
|
|
|
error = EXDEV;
|
1997-09-16 10:11:49 +00:00
|
|
|
if (error == 0) {
|
|
|
|
if (lp->d_secperunit > sp->ds_size)
|
|
|
|
error = ENOSPC;
|
|
|
|
for (part = 0; part < lp->d_npartitions; part++)
|
|
|
|
if (lp->d_partitions[part].p_size > sp->ds_size)
|
|
|
|
error = ENOSPC;
|
|
|
|
}
|
1994-12-12 00:20:34 +00:00
|
|
|
if (error != 0) {
|
|
|
|
free(lp, M_DEVBUF);
|
|
|
|
return (error);
|
|
|
|
}
|
1996-04-19 19:22:29 +00:00
|
|
|
free_ds_label(ssp, slice);
|
1995-02-16 15:19:19 +00:00
|
|
|
set_ds_label(ssp, slice, lp);
|
1999-08-28 14:33:44 +00:00
|
|
|
set_ds_labeldevs(dev, ssp);
|
1994-12-12 00:20:34 +00:00
|
|
|
return (0);
|
|
|
|
|
1995-04-24 17:07:08 +00:00
|
|
|
case DIOCSYNCSLICEINFO:
|
|
|
|
if (slice != WHOLE_DISK_SLICE || dkpart(dev) != RAW_PART)
|
|
|
|
return (EINVAL);
|
1995-04-30 15:16:02 +00:00
|
|
|
if (!*(int *)data)
|
|
|
|
for (slice = 0; slice < ssp->dss_nslices; slice++) {
|
1998-07-20 13:51:11 +00:00
|
|
|
openmask = ssp->dss_slices[slice].ds_openmask;
|
|
|
|
if (openmask
|
1995-04-30 15:16:02 +00:00
|
|
|
&& (slice != WHOLE_DISK_SLICE
|
1998-07-20 13:51:11 +00:00
|
|
|
|| openmask & ~(1 << RAW_PART)))
|
1995-04-30 15:16:02 +00:00
|
|
|
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;
|
1995-04-24 17:07:08 +00:00
|
|
|
lp = malloc(sizeof *lp, M_DEVBUF, M_WAITOK);
|
|
|
|
*lp = *ssp->dss_slices[WHOLE_DISK_SLICE].ds_label;
|
2000-01-16 09:25:34 +00:00
|
|
|
error = dsopen(dev, S_IFCHR, ssp->dss_oflags, sspp, lp);
|
1995-04-30 15:16:02 +00:00
|
|
|
if (error != 0) {
|
|
|
|
free(lp, M_DEVBUF);
|
|
|
|
*sspp = ssp;
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1995-05-08 16:24:08 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
1995-04-30 15:16:02 +00:00
|
|
|
for (slice = 0; slice < ssp->dss_nslices; slice++) {
|
2000-01-16 09:25:34 +00:00
|
|
|
for (openmask = ssp->dss_slices[slice].ds_openmask,
|
1995-05-08 16:24:08 +00:00
|
|
|
part = 0; openmask; openmask >>= 1, part++) {
|
|
|
|
if (!(openmask & 1))
|
1995-04-30 15:16:02 +00:00
|
|
|
continue;
|
1999-09-13 14:12:23 +00:00
|
|
|
error = dsopen(dkmodslice(dkmodpart(dev, part),
|
1995-04-30 15:16:02 +00:00
|
|
|
slice),
|
1998-07-30 15:16:06 +00:00
|
|
|
S_IFCHR, ssp->dss_oflags, sspp,
|
1999-08-14 11:40:51 +00:00
|
|
|
lp);
|
1995-04-30 15:16:02 +00:00
|
|
|
if (error != 0) {
|
|
|
|
free(lp, M_DEVBUF);
|
|
|
|
*sspp = ssp;
|
|
|
|
return (EBUSY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1995-05-08 16:24:08 +00:00
|
|
|
|
1995-04-24 17:07:08 +00:00
|
|
|
free(lp, M_DEVBUF);
|
1995-04-30 15:16:02 +00:00
|
|
|
dsgone(&ssp);
|
|
|
|
return (0);
|
1995-04-24 17:07:08 +00:00
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
case DIOCWDINFO:
|
1999-08-28 14:33:44 +00:00
|
|
|
error = dsioctl(dev, DIOCSDINFO, data, flags, &ssp);
|
1994-12-12 00:20:34 +00:00
|
|
|
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;
|
1995-02-16 15:19:19 +00:00
|
|
|
set_ds_wlabel(ssp, slice, TRUE);
|
1999-08-14 11:40:51 +00:00
|
|
|
error = writedisklabel(dev, sp->ds_label);
|
1995-02-22 21:51:53 +00:00
|
|
|
/* XXX should invalidate in-core label if write failed. */
|
1995-02-16 15:19:19 +00:00
|
|
|
set_ds_wlabel(ssp, slice, old_wlabel);
|
1994-12-12 00:20:34 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
case DIOCWLABEL:
|
1999-05-09 11:27:41 +00:00
|
|
|
#ifndef __alpha__
|
1995-02-16 15:19:19 +00:00
|
|
|
if (slice == WHOLE_DISK_SLICE)
|
|
|
|
return (ENODEV);
|
1999-05-09 11:27:41 +00:00
|
|
|
#endif
|
1994-12-12 00:20:34 +00:00
|
|
|
if (!(flags & FWRITE))
|
|
|
|
return (EBADF);
|
1995-02-16 15:19:19 +00:00
|
|
|
set_ds_wlabel(ssp, slice, *(int *)data != 0);
|
1994-12-12 00:20:34 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
default:
|
1997-12-06 14:27:56 +00:00
|
|
|
return (ENOIOCTL);
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1995-02-18 22:10:44 +00:00
|
|
|
static void
|
|
|
|
dsiodone(bp)
|
2000-05-01 13:36:25 +00:00
|
|
|
struct bio *bp;
|
1995-02-18 22:10:44 +00:00
|
|
|
{
|
|
|
|
struct iodone_chain *ic;
|
1995-02-22 21:51:53 +00:00
|
|
|
char *msg;
|
1995-02-18 22:10:44 +00:00
|
|
|
|
2000-05-01 13:36:25 +00:00
|
|
|
ic = bp->bio_done_chain;
|
|
|
|
bp->bio_done = ic->ic_prev_iodone;
|
|
|
|
bp->bio_done_chain = ic->ic_prev_iodone_chain;
|
|
|
|
if (!(bp->bio_cmd == BIO_READ)
|
|
|
|
|| (!(bp->bio_flags & BIO_ERROR) && bp->bio_error == 0)) {
|
1995-02-22 21:51:53 +00:00
|
|
|
msg = fixlabel((char *)NULL, ic->ic_args[1].ia_ptr,
|
|
|
|
(struct disklabel *)
|
2000-05-01 13:36:25 +00:00
|
|
|
(bp->bio_data + ic->ic_args[0].ia_long),
|
1995-02-22 21:51:53 +00:00
|
|
|
FALSE);
|
|
|
|
if (msg != NULL)
|
|
|
|
printf("%s\n", msg);
|
|
|
|
}
|
1995-02-18 22:10:44 +00:00
|
|
|
free(ic, M_DEVBUF);
|
2000-05-01 13:36:25 +00:00
|
|
|
biodone(bp);
|
1995-02-18 22:10:44 +00:00
|
|
|
}
|
|
|
|
|
1995-02-16 15:19:19 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
1998-07-20 13:39:45 +00:00
|
|
|
/*
|
|
|
|
* Allocate a slices "struct" and initialize it to contain only an empty
|
|
|
|
* compatibility slice (pointing to itself), a whole disk slice (covering
|
|
|
|
* the disk as described by the label), and (nslices - BASE_SLICES) empty
|
|
|
|
* slices beginning at BASE_SLICE.
|
|
|
|
*/
|
|
|
|
struct diskslices *
|
|
|
|
dsmakeslicestruct(nslices, lp)
|
|
|
|
int nslices;
|
|
|
|
struct disklabel *lp;
|
|
|
|
{
|
|
|
|
struct diskslice *sp;
|
|
|
|
struct diskslices *ssp;
|
|
|
|
|
|
|
|
ssp = malloc(offsetof(struct diskslices, dss_slices) +
|
|
|
|
nslices * sizeof *sp, M_DEVBUF, M_WAITOK);
|
|
|
|
ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE;
|
|
|
|
ssp->dss_nslices = nslices;
|
1998-07-30 15:16:06 +00:00
|
|
|
ssp->dss_oflags = 0;
|
1998-07-29 11:15:54 +00:00
|
|
|
ssp->dss_secmult = lp->d_secsize / DEV_BSIZE;
|
|
|
|
if (ssp->dss_secmult & (ssp->dss_secmult - 1))
|
|
|
|
ssp->dss_secshift = -1;
|
|
|
|
else
|
|
|
|
ssp->dss_secshift = ffs(ssp->dss_secmult) - 1;
|
|
|
|
ssp->dss_secsize = lp->d_secsize;
|
1998-07-20 13:39:45 +00:00
|
|
|
sp = &ssp->dss_slices[0];
|
|
|
|
bzero(sp, nslices * sizeof *sp);
|
|
|
|
sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit;
|
|
|
|
return (ssp);
|
|
|
|
}
|
|
|
|
|
1995-02-22 21:51:53 +00:00
|
|
|
char *
|
1999-08-28 14:33:44 +00:00
|
|
|
dsname(dev, unit, slice, part, partname)
|
|
|
|
dev_t dev;
|
1995-02-22 21:51:53 +00:00
|
|
|
int unit;
|
|
|
|
int slice;
|
|
|
|
int part;
|
|
|
|
char *partname;
|
|
|
|
{
|
|
|
|
static char name[32];
|
1999-09-13 14:12:23 +00:00
|
|
|
const char *dname;
|
1995-02-22 21:51:53 +00:00
|
|
|
|
1999-08-28 14:33:44 +00:00
|
|
|
dname = devsw(dev)->d_name;
|
1995-02-22 21:51:53 +00:00
|
|
|
if (strlen(dname) > 16)
|
|
|
|
dname = "nametoolong";
|
1998-12-04 22:54:57 +00:00
|
|
|
snprintf(name, sizeof(name), "%s%d", dname, unit);
|
1995-02-22 21:51:53 +00:00
|
|
|
partname[0] = '\0';
|
|
|
|
if (slice != WHOLE_DISK_SLICE || part != RAW_PART) {
|
|
|
|
partname[0] = 'a' + part;
|
|
|
|
partname[1] = '\0';
|
|
|
|
if (slice != COMPATIBILITY_SLICE)
|
1998-12-04 22:54:57 +00:00
|
|
|
snprintf(name + strlen(name),
|
|
|
|
sizeof(name) - strlen(name), "s%d", slice - 1);
|
1995-02-22 21:51:53 +00:00
|
|
|
}
|
|
|
|
return (name);
|
|
|
|
}
|
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
/*
|
|
|
|
* 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
|
1999-08-28 14:33:44 +00:00
|
|
|
dsopen(dev, mode, flags, sspp, lp)
|
1994-12-12 00:20:34 +00:00
|
|
|
dev_t dev;
|
|
|
|
int mode;
|
1998-07-30 15:16:06 +00:00
|
|
|
u_int flags;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct diskslices **sspp;
|
|
|
|
struct disklabel *lp;
|
|
|
|
{
|
1996-10-29 13:15:30 +00:00
|
|
|
dev_t dev1;
|
1994-12-12 00:20:34 +00:00
|
|
|
int error;
|
1995-03-04 11:42:27 +00:00
|
|
|
struct disklabel *lp1;
|
1994-12-12 00:20:34 +00:00
|
|
|
char *msg;
|
|
|
|
u_char mask;
|
|
|
|
int part;
|
1995-02-22 21:51:53 +00:00
|
|
|
char partname[2];
|
1994-12-12 00:20:34 +00:00
|
|
|
int slice;
|
1995-02-22 21:51:53 +00:00
|
|
|
char *sname;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct diskslice *sp;
|
|
|
|
struct diskslices *ssp;
|
|
|
|
int unit;
|
|
|
|
|
1999-08-29 09:10:05 +00:00
|
|
|
dev->si_bsize_phys = lp->d_secsize;
|
1999-08-23 20:59:21 +00:00
|
|
|
|
1999-06-21 03:48:16 +00:00
|
|
|
unit = dkunit(dev);
|
|
|
|
if (lp->d_secsize % DEV_BSIZE) {
|
1999-08-28 14:33:44 +00:00
|
|
|
printf("%s: invalid sector size %lu\n", devtoname(dev),
|
1999-06-21 03:48:16 +00:00
|
|
|
(u_long)lp->d_secsize);
|
1998-07-29 11:15:54 +00:00
|
|
|
return (EINVAL);
|
1999-06-21 03:48:16 +00:00
|
|
|
}
|
1998-07-29 11:15:54 +00:00
|
|
|
|
1995-02-16 15:19:19 +00:00
|
|
|
/*
|
|
|
|
* XXX reinitialize the slice table unless there is an open device
|
|
|
|
* on the unit. This should only be done if the media has changed.
|
|
|
|
*/
|
1995-02-21 08:38:24 +00:00
|
|
|
ssp = *sspp;
|
2001-05-26 08:27:58 +00:00
|
|
|
if (!dsisopen(ssp)) {
|
|
|
|
if (ssp != NULL)
|
|
|
|
dsgone(sspp);
|
1998-07-20 13:39:45 +00:00
|
|
|
/*
|
|
|
|
* Allocate a minimal slices "struct". This will become
|
|
|
|
* the final slices "struct" if we don't want real slices
|
|
|
|
* or if we can't find any real slices.
|
|
|
|
*/
|
|
|
|
*sspp = dsmakeslicestruct(BASE_SLICE, lp);
|
|
|
|
|
1998-07-30 15:16:06 +00:00
|
|
|
if (!(flags & DSO_ONESLICE)) {
|
|
|
|
TRACE(("dsinit\n"));
|
1999-08-28 14:33:44 +00:00
|
|
|
error = dsinit(dev, lp, sspp);
|
1998-07-30 15:16:06 +00:00
|
|
|
if (error != 0) {
|
|
|
|
dsgone(sspp);
|
|
|
|
return (error);
|
|
|
|
}
|
1995-02-21 08:38:24 +00:00
|
|
|
}
|
|
|
|
ssp = *sspp;
|
1998-07-30 15:16:06 +00:00
|
|
|
ssp->dss_oflags = flags;
|
1995-03-04 11:42:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If there are no real slices, then make the compatiblity
|
|
|
|
* slice cover the whole disk.
|
|
|
|
*/
|
1995-02-21 08:38:24 +00:00
|
|
|
if (ssp->dss_nslices == BASE_SLICE)
|
|
|
|
ssp->dss_slices[COMPATIBILITY_SLICE].ds_size
|
|
|
|
= lp->d_secperunit;
|
1995-03-04 11:42:27 +00:00
|
|
|
|
|
|
|
/* Point the compatibility slice at the BSD slice, if any. */
|
1996-10-29 13:15:30 +00:00
|
|
|
for (slice = BASE_SLICE; slice < ssp->dss_nslices; slice++) {
|
|
|
|
sp = &ssp->dss_slices[slice];
|
1995-03-04 11:42:27 +00:00
|
|
|
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;
|
|
|
|
}
|
1996-10-29 13:15:30 +00:00
|
|
|
}
|
1995-03-04 11:42:27 +00:00
|
|
|
|
1998-07-20 14:35:27 +00:00
|
|
|
ssp->dss_slices[WHOLE_DISK_SLICE].ds_label = clone_label(lp);
|
1995-03-04 11:42:27 +00:00
|
|
|
ssp->dss_slices[WHOLE_DISK_SLICE].ds_wlabel = TRUE;
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
1995-02-16 15:19:19 +00:00
|
|
|
|
2000-09-02 19:17:34 +00:00
|
|
|
/* Initialize secondary info for all slices. */
|
1996-10-29 13:15:30 +00:00
|
|
|
for (slice = 0; slice < ssp->dss_nslices; slice++) {
|
|
|
|
sp = &ssp->dss_slices[slice];
|
1999-05-09 11:27:41 +00:00
|
|
|
if (sp->ds_label != NULL
|
|
|
|
#ifdef __alpha__
|
|
|
|
&& slice != WHOLE_DISK_SLICE
|
|
|
|
#endif
|
|
|
|
)
|
1996-10-29 13:15:30 +00:00
|
|
|
continue;
|
|
|
|
dev1 = dkmodslice(dkmodpart(dev, RAW_PART), slice);
|
2001-05-26 08:27:58 +00:00
|
|
|
#if 0
|
1999-08-28 14:33:44 +00:00
|
|
|
sname = dsname(dev, unit, slice, RAW_PART, partname);
|
2001-05-26 08:27:58 +00:00
|
|
|
#else
|
|
|
|
*partname='\0';
|
|
|
|
sname = dev1->si_name;
|
|
|
|
#endif
|
1996-10-29 13:15:30 +00:00
|
|
|
/*
|
|
|
|
* XXX this should probably only be done for the need_init
|
|
|
|
* case, but there may be a problem with DIOCSYNCSLICEINFO.
|
|
|
|
*/
|
1995-03-04 11:42:27 +00:00
|
|
|
set_ds_wlabel(ssp, slice, TRUE); /* XXX invert */
|
1998-07-20 14:35:27 +00:00
|
|
|
lp1 = clone_label(lp);
|
1995-03-04 11:42:27 +00:00
|
|
|
TRACE(("readdisklabel\n"));
|
1998-07-30 15:16:06 +00:00
|
|
|
if (flags & DSO_NOLABELS)
|
|
|
|
msg = NULL;
|
Write support for the cd(4) driver.
This allows writing to DVD-RAM, PD and similar drives that probe as CD
devices. Note that these are randomly writeable devices, not
sequential-only devices like CD-R drives, which are supported by cdrecord.
Add a new flag value for dsopen(), DSO_COMPATLABEL. The cd(4) driver now
uses this flag instead of the DSO_NOLABELS flag. The DSO_NOLABELS always
used a "fake" disklabel for the entire disk, provided by the caller.
With the DSO_COMPATLABEL flag, dsopen() will first search the media for a
label, and if it finds a label, it will use that label. Otherwise it will
use the fake disklabel provided by the caller. This provides backwards
compatibility, since we will still have labels for ISO9660 media.
It also provides new functionality, since you can now have a regular BSD
disklabel on read-only media, or on writeable media (e.g. DVD-RAM).
Bruce and I both think that we should eventually (in a few years) get
away from using disklabels for ISO9660 media, and just use the whole disk
device (/dev/cd0). At that point disklabel handling in the cd(4) driver
could follow the "normal" model, as used in the da(4) driver.
Also, clean up the path in a couple of places in cdregister(). (Thanks to
Nick Hibma for catching that bug.)
Reviewed by: bde
2000-10-30 07:03:00 +00:00
|
|
|
else {
|
1999-08-14 11:40:51 +00:00
|
|
|
msg = readdisklabel(dev1, lp1);
|
Write support for the cd(4) driver.
This allows writing to DVD-RAM, PD and similar drives that probe as CD
devices. Note that these are randomly writeable devices, not
sequential-only devices like CD-R drives, which are supported by cdrecord.
Add a new flag value for dsopen(), DSO_COMPATLABEL. The cd(4) driver now
uses this flag instead of the DSO_NOLABELS flag. The DSO_NOLABELS always
used a "fake" disklabel for the entire disk, provided by the caller.
With the DSO_COMPATLABEL flag, dsopen() will first search the media for a
label, and if it finds a label, it will use that label. Otherwise it will
use the fake disklabel provided by the caller. This provides backwards
compatibility, since we will still have labels for ISO9660 media.
It also provides new functionality, since you can now have a regular BSD
disklabel on read-only media, or on writeable media (e.g. DVD-RAM).
Bruce and I both think that we should eventually (in a few years) get
away from using disklabels for ISO9660 media, and just use the whole disk
device (/dev/cd0). At that point disklabel handling in the cd(4) driver
could follow the "normal" model, as used in the da(4) driver.
Also, clean up the path in a couple of places in cdregister(). (Thanks to
Nick Hibma for catching that bug.)
Reviewed by: bde
2000-10-30 07:03:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* readdisklabel() returns NULL for success, and an
|
|
|
|
* error string for failure.
|
|
|
|
*
|
|
|
|
* If there isn't a label on the disk, and if the
|
|
|
|
* DSO_COMPATLABEL is set, we want to use the
|
|
|
|
* faked-up label provided by the caller.
|
|
|
|
*
|
|
|
|
* So we set msg to NULL to indicate that there is
|
|
|
|
* no failure (since we have a faked-up label),
|
|
|
|
* free lp1, and then clone it again from lp.
|
|
|
|
* (In case readdisklabel() modified lp1.)
|
|
|
|
*/
|
|
|
|
if (msg != NULL && (flags & DSO_COMPATLABEL)) {
|
|
|
|
msg = NULL;
|
|
|
|
free(lp1, M_DEVBUF);
|
|
|
|
lp1 = clone_label(lp);
|
|
|
|
}
|
|
|
|
}
|
1994-12-12 00:20:34 +00:00
|
|
|
if (msg == NULL)
|
1996-10-29 13:15:30 +00:00
|
|
|
msg = fixlabel(sname, sp, lp1, FALSE);
|
1998-07-29 11:15:54 +00:00
|
|
|
if (msg == NULL && lp1->d_secsize != ssp->dss_secsize)
|
|
|
|
msg = "inconsistent sector size";
|
1994-12-12 00:20:34 +00:00
|
|
|
if (msg != NULL) {
|
1995-03-04 11:42:27 +00:00
|
|
|
if (sp->ds_type == DOSPTYP_386BSD /* XXX */)
|
|
|
|
log(LOG_WARNING, "%s: cannot find label (%s)\n",
|
|
|
|
sname, msg);
|
2000-01-28 11:51:08 +00:00
|
|
|
free(lp1, M_DEVBUF);
|
1996-10-29 13:15:30 +00:00
|
|
|
continue;
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
1996-10-29 13:15:30 +00:00
|
|
|
if (lp1->d_flags & D_BADSECT) {
|
1999-12-08 09:33:00 +00:00
|
|
|
log(LOG_ERR, "%s: bad sector table not supported\n",
|
|
|
|
sname);
|
2000-01-28 11:51:08 +00:00
|
|
|
free(lp1, M_DEVBUF);
|
1999-12-08 09:33:00 +00:00
|
|
|
continue;
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
1996-10-29 13:15:30 +00:00
|
|
|
set_ds_label(ssp, slice, lp1);
|
1999-08-28 14:33:44 +00:00
|
|
|
set_ds_labeldevs(dev1, ssp);
|
1995-03-04 11:42:27 +00:00
|
|
|
set_ds_wlabel(ssp, slice, FALSE);
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
1996-10-29 13:15:30 +00:00
|
|
|
|
|
|
|
slice = dkslice(dev);
|
|
|
|
if (slice >= ssp->dss_nslices)
|
|
|
|
return (ENXIO);
|
|
|
|
sp = &ssp->dss_slices[slice];
|
|
|
|
part = dkpart(dev);
|
1994-12-12 00:20:34 +00:00
|
|
|
if (part != RAW_PART
|
|
|
|
&& (sp->ds_label == NULL || part >= sp->ds_label->d_npartitions))
|
|
|
|
return (EINVAL); /* XXX needs translation */
|
|
|
|
mask = 1 << part;
|
2000-01-16 09:25:34 +00:00
|
|
|
sp->ds_openmask |= mask;
|
1994-12-12 00:20:34 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1995-05-08 16:24:08 +00:00
|
|
|
int
|
1999-08-14 11:40:51 +00:00
|
|
|
dssize(dev, sspp)
|
1995-05-08 16:24:08 +00:00
|
|
|
dev_t dev;
|
|
|
|
struct diskslices **sspp;
|
|
|
|
{
|
|
|
|
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
|
2000-01-16 09:25:34 +00:00
|
|
|
|| !(ssp->dss_slices[slice].ds_openmask & (1 << part))) {
|
|
|
|
if (devsw(dev)->d_open(dev, FREAD, S_IFCHR,
|
2001-09-12 08:38:13 +00:00
|
|
|
(struct thread *)NULL) != 0)
|
1995-05-08 16:24:08 +00:00
|
|
|
return (-1);
|
2001-09-12 08:38:13 +00:00
|
|
|
devsw(dev)->d_close(dev, FREAD, S_IFCHR, (struct thread *)NULL);
|
1995-05-08 16:24:08 +00:00
|
|
|
ssp = *sspp;
|
|
|
|
}
|
|
|
|
lp = ssp->dss_slices[slice].ds_label;
|
|
|
|
if (lp == NULL)
|
|
|
|
return (-1);
|
|
|
|
return ((int)lp->d_partitions[part].p_size);
|
|
|
|
}
|
|
|
|
|
1996-01-27 09:34:21 +00:00
|
|
|
static void
|
1996-04-19 19:22:29 +00:00
|
|
|
free_ds_label(ssp, slice)
|
1996-01-27 09:34:21 +00:00
|
|
|
struct diskslices *ssp;
|
|
|
|
int slice;
|
|
|
|
{
|
|
|
|
struct disklabel *lp;
|
|
|
|
struct diskslice *sp;
|
|
|
|
|
|
|
|
sp = &ssp->dss_slices[slice];
|
|
|
|
lp = sp->ds_label;
|
1996-04-19 19:22:29 +00:00
|
|
|
if (lp == NULL)
|
|
|
|
return;
|
|
|
|
free(lp, M_DEVBUF);
|
|
|
|
set_ds_label(ssp, slice, (struct disklabel *)NULL);
|
|
|
|
}
|
|
|
|
|
1996-01-27 09:34:21 +00:00
|
|
|
|
1994-12-12 00:20:34 +00:00
|
|
|
static char *
|
1995-02-22 21:51:53 +00:00
|
|
|
fixlabel(sname, sp, lp, writeflag)
|
|
|
|
char *sname;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct diskslice *sp;
|
|
|
|
struct disklabel *lp;
|
1995-02-22 21:51:53 +00:00
|
|
|
int writeflag;
|
1994-12-12 00:20:34 +00:00
|
|
|
{
|
1995-02-21 08:38:24 +00:00
|
|
|
u_long end;
|
1995-02-22 21:51:53 +00:00
|
|
|
u_long offset;
|
1995-02-18 22:10:44 +00:00
|
|
|
int part;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct partition *pp;
|
1995-02-21 08:38:24 +00:00
|
|
|
u_long start;
|
1994-12-12 00:20:34 +00:00
|
|
|
bool_t warned;
|
|
|
|
|
1995-02-22 21:51:53 +00:00
|
|
|
/* 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");
|
|
|
|
|
1995-02-21 08:38:24 +00:00
|
|
|
pp = &lp->d_partitions[RAW_PART];
|
1995-02-22 21:51:53 +00:00
|
|
|
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");
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
|
|
|
if (pp->p_size != sp->ds_size) {
|
1995-02-22 21:51:53 +00:00
|
|
|
if (sname != NULL) {
|
|
|
|
printf("%s: raw partition size != slice size\n", sname);
|
|
|
|
slice_info(sname, sp);
|
|
|
|
partition_info(sname, RAW_PART, pp);
|
|
|
|
}
|
1994-12-12 00:20:34 +00:00
|
|
|
if (pp->p_size > sp->ds_size) {
|
1995-02-22 21:51:53 +00:00
|
|
|
if (sname == NULL)
|
|
|
|
return ("fixlabel: raw partition size > slice size");
|
|
|
|
printf("%s: truncating raw partition\n", sname);
|
1994-12-12 00:20:34 +00:00
|
|
|
pp->p_size = sp->ds_size;
|
|
|
|
}
|
|
|
|
}
|
1995-02-21 08:38:24 +00:00
|
|
|
end = start + sp->ds_size;
|
1995-02-22 21:51:53 +00:00
|
|
|
if (start > end)
|
|
|
|
return ("fixlabel: slice wraps");
|
|
|
|
if (lp->d_secpercyl <= 0)
|
|
|
|
return ("fixlabel: d_secpercyl <= 0");
|
1995-02-21 08:38:24 +00:00
|
|
|
pp -= RAW_PART;
|
1994-12-12 00:20:34 +00:00
|
|
|
warned = FALSE;
|
1995-02-18 22:10:44 +00:00
|
|
|
for (part = 0; part < lp->d_npartitions; part++, pp++) {
|
1995-02-21 08:38:24 +00:00
|
|
|
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) {
|
1995-02-22 21:51:53 +00:00
|
|
|
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);
|
1995-02-21 08:38:24 +00:00
|
|
|
}
|
1995-02-22 21:51:53 +00:00
|
|
|
/* XXX else silently discard junk. */
|
1995-02-21 08:38:24 +00:00
|
|
|
bzero(pp, sizeof *pp);
|
|
|
|
} else
|
1995-02-22 21:51:53 +00:00
|
|
|
pp->p_offset += offset;
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
|
|
|
}
|
1995-02-22 21:51:53 +00:00
|
|
|
lp->d_ncylinders = sp->ds_size / lp->d_secpercyl;
|
|
|
|
lp->d_secperunit = sp->ds_size;
|
1995-02-21 08:38:24 +00:00
|
|
|
lp->d_checksum = 0;
|
|
|
|
lp->d_checksum = dkcksum(lp);
|
1994-12-12 00:20:34 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1995-02-22 21:51:53 +00:00
|
|
|
partition_info(sname, part, pp)
|
|
|
|
char *sname;
|
1994-12-12 00:20:34 +00:00
|
|
|
int part;
|
|
|
|
struct partition *pp;
|
|
|
|
{
|
1995-02-22 21:51:53 +00:00
|
|
|
printf("%s%c: start %lu, end %lu, size %lu\n", sname, 'a' + part,
|
1998-07-11 07:46:16 +00:00
|
|
|
(u_long)pp->p_offset, (u_long)(pp->p_offset + pp->p_size - 1),
|
|
|
|
(u_long)pp->p_size);
|
1994-12-12 00:20:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1995-02-22 21:51:53 +00:00
|
|
|
slice_info(sname, sp)
|
|
|
|
char *sname;
|
1994-12-12 00:20:34 +00:00
|
|
|
struct diskslice *sp;
|
|
|
|
{
|
1995-02-22 21:51:53 +00:00
|
|
|
printf("%s: start %lu, end %lu, size %lu\n", sname,
|
1994-12-12 00:20:34 +00:00
|
|
|
sp->ds_offset, sp->ds_offset + sp->ds_size - 1, sp->ds_size);
|
|
|
|
}
|
1995-02-16 15:19:19 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1996-01-27 09:34:21 +00:00
|
|
|
static void
|
1999-08-28 14:33:44 +00:00
|
|
|
set_ds_labeldevs(dev, ssp)
|
1996-01-27 09:34:21 +00:00
|
|
|
dev_t dev;
|
|
|
|
struct diskslices *ssp;
|
1996-04-19 19:22:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
1996-01-27 09:34:21 +00:00
|
|
|
|
1995-02-16 15:19:19 +00:00
|
|
|
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;
|
|
|
|
}
|