mirror of
https://github.com/opnsense/src.git
synced 2026-03-28 13:43:12 -04:00
This code will be turned on with the TWO options DEVFS and SLICE. (see LINT) Two labels PRE_DEVFS_SLICE and POST_DEVFS_SLICE will deliniate these changes. /dev will be automatically mounted by init (thanks phk) on bootup. See /sys/dev/slice/slice.4 for more info. All code should act the same without these options enabled. Mike Smith, Poul Henning Kamp, Soeren, and a few dozen others This code does not support the following: bad144 handling. Persistance. (My head is still hurting from the last time we discussed this) ATAPI flopies are not handled by the SLICE code yet. When this code is running, all major numbers are arbitrary and COULD be dynamically assigned. (this is not done, for POLA only) Minor numbers for disk slices ARE arbitray and dynamically assigned.
827 lines
21 KiB
C
827 lines
21 KiB
C
/*-
|
|
* Copyright (C) 1997,1998 Julian Elischer. All rights reserved.
|
|
* julian@freebsd.org
|
|
*
|
|
* 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``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 HOLDER 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.
|
|
*
|
|
* $Id: $
|
|
*/
|
|
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/disklabel.h>
|
|
#include <sys/diskslice.h>
|
|
#include <sys/dkstat.h>
|
|
#include <sys/malloc.h>
|
|
#include <dev/slice/slice.h>
|
|
|
|
#include <sys/conf.h>
|
|
#include <sys/sliceio.h>
|
|
#include <sys/syslog.h>
|
|
|
|
|
|
struct private_data {
|
|
u_int32_t flags;
|
|
u_int8_t rflags;
|
|
u_int8_t wflags;
|
|
int savedoflags;
|
|
struct slice *slice_down;
|
|
struct disklabel disklabel;
|
|
struct subdev {
|
|
int part;
|
|
struct slice *slice;
|
|
struct slicelimits limit;
|
|
struct private_data *pd;
|
|
u_int32_t offset; /* all disklabel supports */
|
|
} subdevs[MAXPARTITIONS];
|
|
};
|
|
|
|
static sl_h_constructor_t dkl_constructor; /* constructor (from device) */
|
|
static sl_h_IO_req_t dkl_IOreq; /* IO req downward (to device) */
|
|
static sl_h_ioctl_t dkl_ioctl; /* ioctl req downward (to device) */
|
|
static sl_h_open_t dkl_open; /* downwards travelling open */
|
|
static sl_h_close_t dkl_close; /* downwards travelling close */
|
|
static sl_h_claim_t dkl_claim; /* upwards travelling claim */
|
|
static sl_h_revoke_t dkl_revoke;/* upwards travelling revokation */
|
|
static sl_h_verify_t dkl_verify;/* things changed, are we stil valid? */
|
|
static sl_h_upconfig_t dkl_upconfig;/* config requests from below */
|
|
|
|
static struct slice_handler slicetype = {
|
|
"disklabel",
|
|
0,
|
|
NULL,
|
|
0,
|
|
&dkl_constructor, /* constructor */
|
|
&dkl_IOreq,
|
|
&dkl_ioctl,
|
|
&dkl_open,
|
|
&dkl_close,
|
|
&dkl_revoke, /* revoke */
|
|
&dkl_claim, /* claim */
|
|
&dkl_verify, /* verify */
|
|
&dkl_upconfig /* subslice manipulation */
|
|
};
|
|
|
|
static void
|
|
sd_drvinit(void *unused)
|
|
{
|
|
sl_newtype(&slicetype);
|
|
}
|
|
|
|
SYSINIT(sddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sd_drvinit, NULL);
|
|
|
|
/*-
|
|
* Given a slice, extract out our table of information
|
|
*/
|
|
/*-
|
|
* Attempt to read a disk label from a slice.
|
|
* The label must be partly set up before this: secpercyl, secsize
|
|
* and anything required in the strategy routine (e.g., dummy bounds for the
|
|
* partition containing the label) must be filled in before calling us.
|
|
* Returns NULL on success and an error string on failure.
|
|
*/
|
|
static int
|
|
dkl_extract_table(sl_p slice, struct disklabel * lp)
|
|
{
|
|
int error = EINVAL;
|
|
struct buf *bp;
|
|
struct disklabel *dlp;
|
|
struct partition *dp;
|
|
int part;
|
|
int slice_offset; /* XXX */
|
|
|
|
RR;
|
|
/* start off with a known result */
|
|
bzero(lp, sizeof(*lp));
|
|
if (error = slice_readblock(slice, LABELSECTOR, &bp))
|
|
return (error);
|
|
/*
|
|
* Step through the block looking for the label.
|
|
* It may not be at the front (Though I have never seen this).
|
|
* When found, copy it to the destination supplied.
|
|
*/
|
|
error = EINVAL;
|
|
for (dlp = (struct disklabel *) bp->b_data;
|
|
dlp <= (struct disklabel *) ((char *) bp->b_data
|
|
+ slice->limits.blksize
|
|
- sizeof(*dlp));
|
|
dlp = (struct disklabel *) ((char *) dlp + sizeof(long))) {
|
|
if ((dlp->d_magic != DISKMAGIC) ||
|
|
(dlp->d_magic2 != DISKMAGIC) ||
|
|
(dlp->d_npartitions > MAXPARTITIONS) ||
|
|
dkcksum(dlp))
|
|
continue;
|
|
error = 0;
|
|
bcopy(dlp, lp, sizeof(*lp));
|
|
/*
|
|
* disklabels are done relative to the base of the disk,
|
|
* rather than the local partition, (DUH!)
|
|
* so use partition 2 (c) to get the base,
|
|
* and subtract it from all non-0 offsets.
|
|
*/
|
|
dp = lp->d_partitions;
|
|
slice_offset = dp[2].p_offset;
|
|
for (part = 0; part < MAXPARTITIONS; part++, dp++) {
|
|
/*
|
|
* We could be reloading, in which case skip
|
|
* entries already set up.
|
|
*/
|
|
if (dp->p_size == 0)
|
|
continue;
|
|
if( dp->p_offset < slice_offset ) {
|
|
printf("slice before 'c'\n");
|
|
dp->p_size = 0;
|
|
continue;
|
|
}
|
|
dp->p_offset -= slice_offset;
|
|
}
|
|
break;
|
|
}
|
|
|
|
done:
|
|
bp->b_flags |= B_INVAL | B_AGE;
|
|
brelse(bp);
|
|
return (error);
|
|
}
|
|
/*
|
|
* given a table, write it to disk.
|
|
*/
|
|
static int
|
|
dkl_insert_table(sl_p slice, struct disklabel * lp)
|
|
{
|
|
int error = EINVAL;
|
|
struct buf *bp;
|
|
struct disklabel *dlp;
|
|
struct partition *dp;
|
|
int part;
|
|
int slice_offset; /* XXX */
|
|
|
|
RR;
|
|
/* start off with a known result */
|
|
if (error = slice_readblock(slice, LABELSECTOR, &bp))
|
|
return (error);
|
|
/*
|
|
* Step through the block looking for the label.
|
|
* It may not be at the front (Though I have never seen this).
|
|
* When found, replace it witht he new one.
|
|
*/
|
|
error = EINVAL;
|
|
for (dlp = (struct disklabel *) bp->b_data;
|
|
dlp <= (struct disklabel *) ((char *) bp->b_data
|
|
+ slice->limits.blksize
|
|
- sizeof(*dlp));
|
|
dlp = (struct disklabel *) ((char *) dlp + sizeof(long))) {
|
|
if ((dlp->d_magic != DISKMAGIC) ||
|
|
(dlp->d_magic2 != DISKMAGIC) ||
|
|
(dlp->d_npartitions > MAXPARTITIONS) ||
|
|
dkcksum(dlp))
|
|
continue;
|
|
error = 0;
|
|
}
|
|
if (error) {
|
|
/*
|
|
* We didn't find one..
|
|
* so clear the block and place the new disklabel
|
|
* at the start.
|
|
*/
|
|
bzero(bp->b_data, slice->limits.blksize);
|
|
dlp = (struct disklabel *) bp->b_data;
|
|
}
|
|
/*
|
|
* old disklabels are done relative to the base of the disk,
|
|
* rather than the local partition, (DUH!)
|
|
* so use partition 2 (c) to get the base,
|
|
* and subtract it from all non-0 offsets.
|
|
*/
|
|
dp = dlp->d_partitions;
|
|
slice_offset = dp[2].p_offset;
|
|
bcopy(lp, dlp, sizeof(*lp));
|
|
slice_offset -= dp[2].p_offset; /* size we adjust by? */
|
|
for (part = 0; part < MAXPARTITIONS; part++, dp++) {
|
|
if (dp->p_size == 0)
|
|
continue;
|
|
dp->p_offset += slice_offset;
|
|
}
|
|
error = slice_writeblock(slice, LABELSECTOR, bp);
|
|
quit:
|
|
bp->b_flags |= B_INVAL | B_AGE;
|
|
brelse(bp);
|
|
return (error);
|
|
}
|
|
|
|
|
|
|
|
/*-
|
|
* look at a slice and figure out if we should be interested in it. (Is it
|
|
* ours?)
|
|
*/
|
|
static int
|
|
dkl_claim(struct slice * slice, struct slice * lower, void *ID)
|
|
{
|
|
struct disklabel disklabel;
|
|
struct disklabel *dl, *dl0;
|
|
int error;
|
|
RR;
|
|
|
|
/*-
|
|
* Try load a valid disklabel table.
|
|
* This is 90% of what we need to check.
|
|
*/
|
|
if ((error = dkl_extract_table(slice, &disklabel)) != 0) {
|
|
return (error);
|
|
}
|
|
/*-
|
|
* If there is no geometry info, extract it from the label
|
|
* as some drivers need this.
|
|
*/
|
|
/* XXX */
|
|
|
|
/*-
|
|
* well, it looks like one of ours.
|
|
*/
|
|
return (0);
|
|
}
|
|
|
|
/*-
|
|
* This is a special HACK function for the IDE driver.
|
|
* It is here because everything it need is in scope here,
|
|
* but it is not really part of the SLICE code.
|
|
* Because old ESDI drives could not tell their geometry, They need
|
|
* to get it from the MBR or the disklabel. This is the disklabel bit.
|
|
*/
|
|
int
|
|
dkl_geom_hack(struct slice * slice, struct ide_geom *geom)
|
|
{
|
|
struct disklabel disklabel;
|
|
struct disklabel *dl, *dl0;
|
|
int error;
|
|
RR;
|
|
|
|
/* first check it's a disklabel*/
|
|
if ((error = dkl_claim (slice, NULL, 0)))
|
|
return (error);
|
|
/*-
|
|
* Try load a valid disklabel table.
|
|
* This is wasteful but never called on new (< 5 YO ) drives.
|
|
*/
|
|
if ((error = dkl_extract_table(slice, &disklabel)) != 0) {
|
|
return (error);
|
|
}
|
|
geom->secpertrack = disklabel. d_nsectors;
|
|
geom->trackpercyl = disklabel.d_ntracks;
|
|
geom->cyls = disklabel.d_ncylinders;
|
|
return (0);
|
|
}
|
|
|
|
/*-
|
|
* look at a slice we know to be ours and decide what the #$%^ to do with it.
|
|
*/
|
|
static int
|
|
dkl_constructor(sl_p slice)
|
|
{
|
|
int i;
|
|
u_int64_t disksize = slice->limits.slicesize;
|
|
struct private_data *pd;
|
|
struct partition *dp, *dp0;
|
|
struct disklabel *dl;
|
|
sh_p tp;
|
|
char name[64];
|
|
|
|
int part;
|
|
int error = 0;
|
|
u_long dkl_offset;
|
|
|
|
RR;
|
|
/*-
|
|
* If we are being called to re-load a slice,
|
|
* then don't reallocate resources.
|
|
*/
|
|
if ((pd = slice->private_up) == NULL) {
|
|
if (slice->name == NULL) {
|
|
printf("name is NULL\n");
|
|
return (EINVAL);
|
|
}
|
|
if (strlen(slice->name) > 58) {
|
|
printf("slice: name %s too long\n", slice->name);
|
|
return (ENAMETOOLONG);
|
|
}
|
|
pd = malloc(sizeof(*pd), M_DEVBUF, M_NOWAIT);
|
|
if (pd == NULL) {
|
|
printf("fdisk: failed malloc\n");
|
|
return (ENOMEM);
|
|
}
|
|
bzero(pd, sizeof(*pd));
|
|
pd->slice_down = slice;
|
|
if ((error = dkl_extract_table(slice, &pd->disklabel)) != 0) {
|
|
struct partinfo data;
|
|
/*
|
|
* If it's just that there is no disklabel there,
|
|
* Then we fake one up and write it. if this were
|
|
* not ok, then we would have not been called.
|
|
* (as probe will have failed). If it's
|
|
* a physical error, then that's reason to fail.
|
|
*/
|
|
if (error != EINVAL) {
|
|
free(pd, M_DEVBUF);
|
|
return (error);
|
|
}
|
|
dkl_dummy_ioctl(slice, DIOCGPART,
|
|
(caddr_t) &data, 0, NULL);
|
|
bcopy(data.disklab, &pd->disklabel,
|
|
sizeof(pd->disklabel));
|
|
if ((error = dkl_insert_table(slice, &pd->disklabel))) {
|
|
free(pd, M_DEVBUF);
|
|
return (error);
|
|
}
|
|
}
|
|
slice->refs++;
|
|
slice->handler_up = &slicetype;
|
|
slice->private_up = pd;
|
|
slicetype.refs++;
|
|
}
|
|
dl = &pd->disklabel;
|
|
dp0 = dl->d_partitions;
|
|
|
|
/*-
|
|
* Handle each of the partitions.
|
|
* We should check that each makes sence and is legal.
|
|
* 1/ it should not already have a slice.
|
|
* 2/ should not be 0 length.
|
|
* 3/ should not go past end of our slice.
|
|
* 4/ should not overlap other slices.
|
|
* It can include sector 0 (unfortunatly)
|
|
*/
|
|
dp = dp0;
|
|
for (part = 0; part < MAXPARTITIONS; part++, dp++) {
|
|
int i;
|
|
if ( part == 2 )
|
|
continue; /* XXX skip the 'c' partition */
|
|
/*
|
|
* We could be reloading, in which case skip
|
|
* entries already set up.
|
|
*/
|
|
if (pd->subdevs[part].slice != NULL)
|
|
breakout: continue;
|
|
/*
|
|
* also skip partitions not present
|
|
*/
|
|
if (dp->p_size == 0)
|
|
continue;
|
|
printf(" part %d, start=%d, size=%d\n", part, dp->p_offset, dp->p_size);
|
|
|
|
if ((dp->p_offset + dp->p_size) >
|
|
(slice->limits.slicesize / slice->limits.blksize)) {
|
|
printf("dkl: slice %d too big ", part);
|
|
printf("(%x > %x:%x )\n",
|
|
(dp->p_offset + dp->p_size),
|
|
(slice->limits.slicesize / slice->limits.blksize) );
|
|
continue;
|
|
}
|
|
/* check for overlaps with existing slices */
|
|
for (i = 0; i < MAXPARTITIONS; i++) {
|
|
/*
|
|
* Don't bother if that slice was not made.
|
|
* This handles the (i == part) case.
|
|
*/
|
|
if (pd->subdevs[i].slice == NULL)
|
|
continue;
|
|
if ((dp0[i].p_offset < (dp->p_offset + dp->p_size))
|
|
&& ((dp0[i].p_offset + dp0[i].p_size) > dp->p_offset)) {
|
|
printf("dkl: slice %d overlaps slice %d\n",
|
|
part, i);
|
|
goto breakout;
|
|
}
|
|
}
|
|
/*-
|
|
* the slice seems to make sense. Use it.
|
|
*/
|
|
pd->subdevs[part].part = part;
|
|
pd->subdevs[part].pd = pd;
|
|
pd->subdevs[part].offset = dp->p_offset;
|
|
pd->subdevs[part].limit.blksize
|
|
= slice->limits.blksize;
|
|
pd->subdevs[part].limit.slicesize
|
|
= (slice->limits.blksize * (u_int64_t)dp->p_size);
|
|
|
|
sprintf(name, "%s%c", slice->name, (char )('a' + part));
|
|
sl_make_slice(&slicetype,
|
|
&pd->subdevs[part],
|
|
&pd->subdevs[part].limit,
|
|
&pd->subdevs[part].slice,
|
|
NULL,
|
|
name);
|
|
pd->subdevs[part].slice->probeinfo.typespecific = &dp->p_fstype;
|
|
switch (dp->p_fstype) {
|
|
case FS_UNUSED:
|
|
/* allow unuseed to be further split */
|
|
pd->subdevs[part].slice->probeinfo.type = NULL;
|
|
break;
|
|
case FS_V6:
|
|
case FS_V7:
|
|
case FS_SYSV:
|
|
case FS_V71K:
|
|
case FS_V8:
|
|
case FS_MSDOS:
|
|
case FS_BSDLFS:
|
|
case FS_OTHER:
|
|
case FS_HPFS:
|
|
case FS_ISO9660:
|
|
case FS_BOOT :
|
|
#if 0
|
|
printf("%s: type %d. Leaving\n",
|
|
pd->subdevs[part].slice->name,
|
|
(u_int)dp->p_fstype);
|
|
#endif
|
|
case FS_SWAP:
|
|
case FS_BSDFFS:
|
|
pd->subdevs[part].slice->probeinfo.type = NO_SUBPART;
|
|
break;
|
|
default:
|
|
pd->subdevs[part].slice->probeinfo.type = NULL;
|
|
}
|
|
/*
|
|
* Dont allow further breakup of slices that
|
|
* cover our disklabel
|
|
*/
|
|
if (dp->p_offset < 16) {
|
|
#if 0
|
|
printf("%s: covers disklabel. Leaving\n",
|
|
pd->subdevs[part].slice->name);
|
|
#endif
|
|
pd->subdevs[part].slice->probeinfo.type = NO_SUBPART;
|
|
}
|
|
if ((tp = slice_probeall(pd->subdevs[part].slice)) != NULL) {
|
|
(*tp->constructor)(pd->subdevs[part].slice);
|
|
}
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
/*-
|
|
* look at a slice that USED to be ours.
|
|
* decide if any sub-slices need to be revoked.
|
|
* If not then at least ask them to verify themselves.
|
|
*/
|
|
static int
|
|
dkl_verify(sl_p slice)
|
|
{
|
|
register struct private_data *pd;
|
|
struct disklabel label;
|
|
struct partition *dp, *dp2;
|
|
struct disklabel *dl;
|
|
int part;
|
|
int error;
|
|
/* register struct slice *slice; */
|
|
|
|
RR;
|
|
pd = slice->private_up;
|
|
/* slice = pd->slice_down; */
|
|
bzero(&label, sizeof(label));
|
|
/*
|
|
* Try load a valid disklabel. This is 90% of what we need to check.
|
|
*/
|
|
if (((error = dkl_extract_table(slice, &label)) != 0)
|
|
|| (slice->limits.blksize != 512)) {
|
|
/*-
|
|
* Oh oh, we need to invalidate all the subslices.
|
|
* and relinquish this slice.
|
|
*/
|
|
return (dkl_revoke(pd));
|
|
}
|
|
dl = &(pd->disklabel);
|
|
dp = dl->d_partitions;
|
|
dp2 = label.d_partitions;
|
|
for (part = 0; part < MAXPARTITIONS; part++, dp++, dp2++) {
|
|
if (pd->subdevs[part].slice) {
|
|
if ((dp2->p_offset != dp->p_offset)
|
|
|| (dp2->p_size != dp->p_size)) {
|
|
sl_rmslice(pd->subdevs[part].slice);
|
|
pd->subdevs[part].slice = NULL;
|
|
} else if (pd->subdevs[part].slice->handler_up) {
|
|
(*pd->subdevs[part].slice->handler_up->verify)
|
|
(pd->subdevs[part].slice);
|
|
}
|
|
}
|
|
}
|
|
/*- having got rid of changing slices, replace
|
|
* the old table with the new one, and
|
|
* handle any new slices by calling the constructor.
|
|
*/
|
|
bcopy(&label, dl, sizeof(label));
|
|
error = dkl_constructor(slice);
|
|
done:
|
|
return (error);
|
|
}
|
|
|
|
/*-
|
|
* Invalidate all subslices, and free resources for this handler instance.
|
|
*/
|
|
static int
|
|
dkl_revoke(void *private)
|
|
{
|
|
register struct private_data *pd;
|
|
register struct slice *slice;
|
|
int part;
|
|
|
|
RR;
|
|
pd = private;
|
|
slice = pd->slice_down;
|
|
for (part = 0; part < MAXPARTITIONS; part++) {
|
|
if (pd->subdevs[part].slice) {
|
|
sl_rmslice(pd->subdevs[part].slice);
|
|
}
|
|
}
|
|
/*-
|
|
* remove ourself as a handler
|
|
*/
|
|
slice->handler_up = NULL;
|
|
slice->private_up = NULL;
|
|
slicetype.refs--;
|
|
free(pd, M_DEVBUF);
|
|
sl_unref(slice);
|
|
return (0);
|
|
}
|
|
|
|
/*-
|
|
* shift the appropriate IO by the offset for that slice.
|
|
*/
|
|
static void
|
|
dkl_IOreq(void *private, struct buf * bp)
|
|
{
|
|
register struct private_data *pd;
|
|
struct subdev *sdp;
|
|
register struct slice *slice;
|
|
|
|
RR;
|
|
sdp = private;
|
|
pd = sdp->pd;
|
|
slice = pd->slice_down;
|
|
bp->b_pblkno += sdp->offset; /* add the offset for that slice */
|
|
sliceio(slice, bp, SLW_ABOVE);
|
|
}
|
|
|
|
/*
|
|
* shift the appropriate IO by the offset for that slice.
|
|
*/
|
|
static void
|
|
mbr_IOreq(void *private, struct buf * bp)
|
|
{
|
|
register struct private_data *pd;
|
|
struct subdev *sdp;
|
|
register struct slice *slice;
|
|
|
|
RR;
|
|
sdp = private;
|
|
pd = sdp->pd;
|
|
slice = pd->slice_down;
|
|
bp->b_pblkno += sdp->offset; /* add the offset for that slice */
|
|
sliceio(slice, bp, SLW_ABOVE);
|
|
}
|
|
|
|
static int
|
|
dkl_open(void *private, int flags, int mode, struct proc * p)
|
|
{
|
|
register struct private_data *pd;
|
|
struct subdev *sdp;
|
|
register struct slice *slice;
|
|
int error;
|
|
u_int8_t newrflags = 0;
|
|
u_int8_t newwflags = 0;
|
|
int newoflags;
|
|
int part;
|
|
u_int8_t partbit;
|
|
|
|
RR;
|
|
sdp = private;
|
|
part = sdp->part;
|
|
partbit = (1 << part);
|
|
pd = sdp->pd;
|
|
slice = pd->slice_down;
|
|
|
|
/*
|
|
* Calculate the change to to over-all picture here.
|
|
* Notice that this might result in LESS open bits
|
|
* if that was what was passed from above.
|
|
* (Prelude to 'mode-change' instead of open/close.)
|
|
*/
|
|
/* work out what our stored flags will be if this succeeds */
|
|
newwflags &= ~ (partbit);
|
|
newrflags &= ~ (partbit);
|
|
newwflags |= (flags & FWRITE) ? (partbit) : 0;
|
|
newrflags |= (flags & FREAD) ? (partbit) : 0;
|
|
|
|
/* work out what we want to pass down this time */
|
|
newoflags = newwflags ? FWRITE : 0;
|
|
newoflags |= newrflags ? FREAD : 0;
|
|
|
|
/*
|
|
* If the agregate flags we used last time are the same as
|
|
* the agregate flags we would use this time, then don't
|
|
* bother re-doing the command.
|
|
*/
|
|
if (newoflags != pd->savedoflags) {
|
|
if (error = sliceopen(slice, newoflags, mode, p, SLW_ABOVE)) {
|
|
return (error);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now that we know it succeeded, commit, by replacing the old
|
|
* flags with the new ones.
|
|
*/
|
|
pd->rflags = newrflags;
|
|
pd->wflags = newwflags;
|
|
pd->savedoflags = newoflags;
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
dkl_close(void *private, int flags, int mode, struct proc * p)
|
|
{
|
|
register struct private_data *pd;
|
|
struct subdev *sdp;
|
|
register struct slice *slice;
|
|
u_int8_t newrflags = 0;
|
|
u_int8_t newwflags = 0;
|
|
int newoflags;
|
|
int part;
|
|
u_int8_t partbit;
|
|
|
|
RR;
|
|
sdp = private;
|
|
part = sdp->part;
|
|
partbit = (1 << part);
|
|
pd = sdp->pd;
|
|
slice = pd->slice_down;
|
|
|
|
if ((pd->rflags == 0) && (pd->wflags == 0))
|
|
return;
|
|
|
|
/* work out what our stored flags will be if this succeeds */
|
|
newwflags &= ~ (partbit);
|
|
newrflags &= ~ (partbit);
|
|
newwflags |= (flags & FWRITE) ? (partbit) : 0;
|
|
newrflags |= (flags & FREAD) ? (partbit) : 0;
|
|
|
|
/* work out what we want to pass down this time */
|
|
newoflags = newwflags ? FWRITE : 0;
|
|
newoflags |= newrflags ? FREAD : 0;
|
|
|
|
/*
|
|
* If this was the last open slice above, then release our own open
|
|
*/
|
|
if ((pd->rflags == 0) && (pd->wflags == 0)) {
|
|
sliceclose(slice, newoflags, mode, p, SLW_ABOVE);
|
|
}
|
|
pd->rflags = newrflags;
|
|
pd->wflags = newwflags;
|
|
pd->savedoflags = newoflags;
|
|
return ;
|
|
}
|
|
|
|
static int
|
|
dkl_ioctl(void *private, int cmd, caddr_t addr, int flag, struct proc * p)
|
|
{
|
|
register struct private_data *pd;
|
|
struct subdev *sdp;
|
|
register struct slice *slice;
|
|
struct disklabel *lp;
|
|
int error;
|
|
|
|
RR;
|
|
sdp = private;
|
|
pd = sdp->pd;
|
|
slice = pd->slice_down;
|
|
lp = &pd->disklabel;
|
|
switch (cmd) {
|
|
case DIOCGDINFO:
|
|
*(struct disklabel *)addr = *lp;
|
|
return (0);
|
|
|
|
case DIOCGPART:
|
|
if (lp == NULL)
|
|
return (EINVAL);
|
|
((struct partinfo *)addr)->disklab = lp;
|
|
((struct partinfo *)addr)->part = lp->d_partitions + sdp->part;
|
|
return (0);
|
|
|
|
/* These don't really make sense. keep the headers for a reminder */
|
|
case DIOCSDINFO:
|
|
case DIOCSYNCSLICEINFO:
|
|
case DIOCWDINFO:
|
|
case DIOCWLABEL:
|
|
return (ENOIOCTL);
|
|
}
|
|
|
|
return ((*slice->handler_down->ioctl) (slice->private_down,
|
|
cmd, addr, flag, p));
|
|
}
|
|
|
|
static int
|
|
dkl_upconfig(struct slice *slice, int cmd, caddr_t addr, int flag, struct proc * p)
|
|
{
|
|
RR;
|
|
switch (cmd) {
|
|
case SLCIOCRESET:
|
|
return (0);
|
|
|
|
/* These don't really make sense. keep the headers for a reminder */
|
|
default:
|
|
return (ENOIOCTL);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static struct disklabel static_label;
|
|
/*
|
|
* This is a hack routine called from the slice generic code to produce a dummy
|
|
* disklabel when given a slice descriptor. It's in here because this code
|
|
* knows about disklabels.
|
|
*/
|
|
int
|
|
dkl_dummy_ioctl(struct slice *slice, int cmd, caddr_t addr,
|
|
int flag, struct proc * p)
|
|
{
|
|
struct disklabel *lp = &static_label;
|
|
|
|
switch (cmd) {
|
|
case DIOCGDINFO:
|
|
case DIOCGPART:
|
|
bzero(lp, sizeof(static_label));
|
|
lp->d_magic = DISKMAGIC;
|
|
lp->d_magic2 = DISKMAGIC;
|
|
lp->d_secsize = slice->limits.blksize;
|
|
lp->d_nsectors = 1;
|
|
lp->d_ntracks = 1;
|
|
lp->d_secpercyl = 1;
|
|
lp->d_ncylinders =
|
|
lp->d_secperunit = slice->limits.slicesize
|
|
/ slice->limits.blksize;
|
|
lp->d_npartitions = RAW_PART + 1;
|
|
lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
|
|
lp->d_partitions[RAW_PART].p_offset = 0;
|
|
break;
|
|
default:
|
|
return (ENOIOCTL);
|
|
}
|
|
lp->d_checksum = dkcksum(lp);
|
|
|
|
switch (cmd) {
|
|
case DIOCGDINFO:
|
|
*(struct disklabel *)addr = *lp;
|
|
break;
|
|
case DIOCGPART:
|
|
/* XXX hack alert.
|
|
* This is a hack as this information is consumed immediatly
|
|
* otherwise the use of a static buffer would be dangerous.
|
|
*/
|
|
((struct partinfo *)addr)->disklab = lp;
|
|
((struct partinfo *)addr)->part = lp->d_partitions + RAW_PART;
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
#if 0 /* use the existing one for now */
|
|
/*-
|
|
* Compute checksum for disk label.
|
|
*/
|
|
u_int
|
|
dkcksum(lp)
|
|
register struct disklabel *lp;
|
|
{
|
|
register u_short *start, *end;
|
|
register u_short sum = 0;
|
|
|
|
start = (u_short *) lp;
|
|
end = (u_short *) & lp->d_partitions[lp->d_npartitions];
|
|
while (start < end)
|
|
sum ^= *start++;
|
|
return (sum);
|
|
}
|
|
#endif /* 0 */
|
|
|