opnsense-src/sys/dev/slice/slice_base.c
Julian Elischer 3e425b968d Add changes and code to implement a functional DEVFS.
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.
1998-04-19 23:32:49 +00:00

671 lines
19 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/systm.h>
#include <sys/kernel.h> /* SYSINIT stuff */
#include <sys/fcntl.h> /* FREAD/FWRITE */
#include <sys/conf.h> /* cdevsw stuff */
#include <sys/malloc.h> /* malloc region definitions */
#include <sys/buf.h> /* buffers for IO */
#include <sys/queue.h> /* linked lists etc. */
#include <sys/stat.h> /* S_IFCHR, S_IFBLK */
#include <sys/sysctl.h> /* the sysctl for shooting self in foot */
/*#include <sys/devfsext.h> */ /* DEVFS defintitions */
#include <dev/slice/slice.h> /* temporary location */
#define SLICESPL() splbio()
static int slicexclusive = 0; /* default value == "foot shootable" */
/*
* Make a new type available. Just link it in, but first make sure there is
* no name collision.
*/
static sh_p types;
int
sl_newtype(sh_p tp)
{
if (sl_findtype(tp->name)) {
return (EEXIST);
}
tp->next = types;
types = tp;
return (0);
}
/*
* Look for a type of the name given.
*/
sh_p
sl_findtype(char *type)
{
sh_p tp;
tp = types;
while (tp) {
if (strcmp(tp->name, type) == 0)
return (tp);
tp = tp->next;
}
return (NULL);
}
/*
* Ask all known handler types if a given slice is handled by them.
* If the slice specifies a type, then just find that.
*/
sh_p
slice_probeall(sl_p slice)
{
sh_p tp = types;
if (slice->probeinfo.type == NULL) {
while (tp) {
printf("%s: probing for %s.. ",slice->name, tp->name);
if ((*tp->claim) (slice, NULL, NULL) == 0) {
printf("yep\n");
return (tp);
}
printf("nope\n");
tp = tp->next;
}
/*
* Null string ("") means "don't even try". Caller probably should
* pre-trap such cases but we'll check here too.
*/
} else if (slice->probeinfo.type[0]) {
tp = sl_findtype(slice->probeinfo.type);
if ((tp) && ((*tp->claim) (slice, NULL, NULL) == 0)) {
printf("%s: attaching %s..\n",slice->name, tp->name);
return (tp);
}
}
/*printf("%s: Leaving as raw device\n", slice->name); */
return (NULL);
}
/*
* Make a handler instantiation of the requested type.
*
*/
static int
sl_make_handler(char *type, sl_p slice)
{
sh_p handler_up;
void *private_up;
int errval;
/*
* check that the type makes sense.
*/
if (type == NULL) {
return (EINVAL);
}
handler_up = sl_findtype(type);
if (handler_up == NULL) {
return (ENXIO);
}
/*
* and call the constructor
*/
if (handler_up->constructor != NULL) {
errval = (*handler_up->constructor) (slice);
return (errval);
} else {
printf("slice handler %s has no constructor\n",
handler_up->name);
return (EINVAL);
}
}
/*
* lock and unlock Slices while doing operations such as open().
* gets a reference on the slice..
* XXX This doesn't work for SMP.
*/
int
lockslice(struct slice *slice)
{
int s = SLICESPL();
slice->refs++;
while ( slice->flags & (SLF_LOCKED | SLF_INVALID)) {
if (slice->flags & SLF_INVALID) {
sl_unref(slice);
splx(s);
return (ENXIO);
}
slice->flags |= SLF_WANTED;
tsleep(slice, PRIBIO, "lockslice", 0);
}
slice->flags |= SLF_LOCKED;
splx(s);
return (0);
}
/*
* Releases a slice
* Assumes that if we had it locked, no-one else could invalidate it.
* We can still hold a reference on it.
*/
int
unlockslice(struct slice *slice)
{
int s = SLICESPL();
slice->flags &= ~SLF_LOCKED;
if ( slice->flags & SLF_WANTED) {
slice->flags &= ~SLF_WANTED;
wakeup(slice);
}
splx(s);
return (0);
}
/*
* create a new slice. Link it into the structures. don't yet find and call
* it's type handler. That's done later
*/
int
sl_make_slice(sh_p handler_down, void *private_down,
struct slicelimits * limits,
sl_p * slicepp, char *type, char *name)
{
sl_p slice;
/*
* Allocate storage for this instance .
*/
slice = malloc(sizeof(*slice), M_DEVBUF, M_NOWAIT);
if (slice == NULL) {
printf("slice failed to allocate driver storage\n");
return (ENOMEM);
}
bzero(slice, sizeof(*slice));
if (name) {
slice->name = malloc(strlen(name) + 1, M_DEVBUF, M_NOWAIT);
if (slice->name == NULL) {
printf("slice failed name storage\n");
free(slice, M_DEVBUF);
return (ENOMEM);
}
strcpy(slice->name, name);
}
slice->handler_down = handler_down;
slice->private_down = private_down;
handler_down->refs++;
slice->limits = *limits;
slice_add_device(slice);
slice->refs = 1; /* one for our downward creator */
*slicepp = slice;
if (type) {
slice->refs++; /* don't go away *//* probably not needed */
sl_make_handler(type, slice);
sl_unref(slice);
}
return (0);
}
/*
* Forceably start a shutdown process on a slice. Either call it's shutdown
* method, or do the default shutdown if there is no type-specific method.
* XXX Really should say who called us.
*/
void
sl_rmslice(sl_p slice)
{
RR;
/*
* An extra reference so it doesn't go away while we are not looking.
*/
slice->refs++;
if (slice->flags & SLF_INVALID) {
/*
* If it's already shutting down, let it die without further
* taunting. "go away or I'll taunt you a second time, you
* silly eenglish pig-dog"
*/
sl_unref(slice);/* possibly the last reference */
return;
}
/*
* Mark it as invalid so any newcomers know not to try use it.
* No real need to LOCK it.
*/
slice->flags &= ~SLF_OPEN_STATE;
slice->flags |= SLF_INVALID;
/*
* remove the device appendages.
* Any open vnodes SHOULD go to deadfs.
*/
slice_remove_device(slice);
/*
* Propogate the damage upwards.
* Note that the revoke method is not optional.
* The upper handler releases it's reference so refs--.
*/
if (slice->handler_up) {
(*slice->handler_up->revoke) (slice->private_up);
}
sl_unref(slice); /* One for the lower handler that called us */
sl_unref(slice); /* possibly the last reference */
}
void
sl_unref(sl_p slice)
{
if ((--(slice->refs)) == 0) {
FREE(slice, M_DEVBUF);
}
}
/*
* Read a block on behalf of a handler.
* This is not a bulk IO routine but meant for probes etc.
* I think that perhaps it should attempt to do sliceopen()
* calls on the slice first. (XXX?)
*/
int
slice_readblock(struct slice * slice, int blkno, struct buf ** bpp)
{
struct buf *bp;
int error = 0;
/*
* posibly attempt to open device?
*/
/* --not yet-- */
/*
* Now that it is open, get the buffer and set in the parameters.
*/
bp = geteblk((int) slice->limits.blksize);
if (bp == NULL) {
return (ENOMEM);
}
bp->b_pblkno = bp->b_blkno = blkno;
bp->b_bcount = slice->limits.blksize;
bp->b_flags |= B_BUSY | B_READ;
sliceio(slice, bp, SLW_ABOVE);
if (biowait(bp) != 0) {
printf("failure reading device block\n");
error = EIO;
bp->b_flags |= B_INVAL | B_AGE;
brelse(bp);
bp = NULL;
}
*bpp = bp;
return (error);
}
/*
* Read a block on behalf of a handler.
* This is not a bulk IO routine but meant for probes etc.
* I think that perhaps it should attempt to do sliceopen()
* calls on the slice first. (XXX?)
*/
int
slice_writeblock(struct slice * slice, int blkno, struct buf * bp)
{
int error = 0;
if (bp == NULL) {
return (ENOMEM);
}
bp->b_pblkno = bp->b_blkno = blkno;
bp->b_bcount = slice->limits.blksize;
bp->b_flags |= B_BUSY | B_WRITE;
sliceio(slice, bp, SLW_ABOVE);
if (biowait(bp) != 0) {
printf("failure reading device block\n");
error = EIO;
}
return (error);
}
/*
* functions that are used to call the next level down.
*/
void
sliceio(sl_p slice, struct buf * bp, enum slc_who who)
{
/* XXX do shortcuts here */
if (slice->flags & SLF_INVALID) {
bp->b_error = ENXIO;
goto bad;
}
/*
* if it's from above, assume it hasn't
* broken it's agreement about read/write.
* A higher level slice would have caught it.
* Make no such assumption if it's this device.
*/
if (who == SLW_DEVICE) {
if (((slice->flags & SLF_OPEN_DEV_WR) == 0) &&
( (bp->b_flags & B_READ) == B_WRITE )) {
bp->b_error = EROFS;
goto bad;
}
}
(*slice->handler_down->IOreq) (slice->private_down, bp);
return;
bad:
bp->b_flags |= B_ERROR;
/* toss transfer, we're done early */
biodone(bp);
return;
}
/*
* Try open a slice.
* don't forget to say if we are above (1) or the dev (0).
*
* We really need to add a lot of support for CHANGING
* what we have openned.. i.e if we have ABOVE open R/W
* and DEVICE open R/O, then closing the device
* should downgrade our open to those items below us to R/O.
* This would need support in both open and close routines in both
* slice and handler code.
*
* ((*) == Illegal state.. (how did we get here?))
* (must have been in "shoot foot mode").
* A bit already set can be set again. (may represent part of an upgrade)
* This may not hold true if we are in an 'illegal state'.
* Some such opens will fail in an attempt to revert to a legal state.
* success = ((request & allowed[state]) == request)
*/
#define UP_RDWR SLF_OPEN_UP
#define CHR_RDWR SLF_OPEN_CHR
#define CHR_RD SLF_OPEN_CHR_RD
#define BLK_RDWR SLF_OPEN_BLK
#define BLK_RD SLF_OPEN_BLK_RD
static u_char allowed[64] = {
/* Present state | requested states allowed */
/* UP CHR BLK | UP CHR BLK */
/* R W R W R W | R W R W R W */
/* 0 0 0 0 0 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ),
/* 0 0 0 0 0 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ),
/* 0 0 0 0 1 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ),
/* 0 0 0 0 1 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ),
/* 0 0 0 1 0 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ),
/* 0 0 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 0 0 1 1 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ),
/* 0 0 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 0 1 0 0 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ),
/* 0 0 1 0 0 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ),
/* 0 0 1 0 1 0 1 1 1 1 1 1 */( UP_RDWR|CHR_RDWR|BLK_RDWR ),
/* 0 0 1 0 1 1 0 0 1 0 1 1 */( CHR_RD|BLK_RDWR ),
/* 0 0 1 1 0 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ),
/* 0 0 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 0 1 1 1 0 0 0 1 1 1 0 */( CHR_RDWR|BLK_RD ),
/* 0 0 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 0 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 0 1 0 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 0 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 0 1 0 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 0 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 0 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 1 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 0 1 1 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 1 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 0 1 1 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 1 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 1 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 0 1 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 0 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 0 0 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 0 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 0 0 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 0 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 0 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 1 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 0 1 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 1 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 0 1 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 1 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 1 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 0 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 0 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 1 0 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 0 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 1 0 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 0 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 0 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 0 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 0 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 1 0 0 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 1 1 0 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 1 0 1 0 1 1 1 0 1 0 */( UP_RDWR|CHR_RD|BLK_RD ),
/* 1 1 1 0 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 1 1 0 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 1 1 0 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 1 1 1 0 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ),
/* 1 1 1 1 1 1 0 0 1 0 1 0 (*) */( CHR_RD|BLK_RD ) };
int
sliceopen(struct slice *slice, int flags, int mode,
struct proc * p, enum slc_who who)
{
int s;
int error;
int sl_flags = slice->flags & SLF_OPEN_STATE;
int or_flags;
int and_flags;
int dn_flags;
int odn_flags;
if (slice->flags & SLF_INVALID)
return (ENXIO);
/*
* Firstly, don't allow re-opens of what is already open
*/
if (error = lockslice(slice))
return (error);
error = EBUSY; /* default answer */
switch (who) {
case SLW_ABOVE:
or_flags = ((flags & FREAD) ? SLF_OPEN_UP_RD : 0);
or_flags |= ((flags & FWRITE) ? SLF_OPEN_UP_WR : 0);
and_flags = ~SLF_OPEN_UP;
break;
case SLW_DEVICE:
switch (mode & S_IFMT) {
case S_IFCHR:
or_flags = ((flags & FREAD) ? SLF_OPEN_CHR_RD : 0);
or_flags |= ((flags & FWRITE) ? SLF_OPEN_CHR_WR : 0);
and_flags = ~SLF_OPEN_CHR;
break;
case S_IFBLK:
or_flags = ((flags & FREAD) ? SLF_OPEN_BLK_RD : 0);
or_flags |= ((flags & FWRITE) ? SLF_OPEN_BLK_WR : 0);
and_flags = ~SLF_OPEN_BLK;
break;
default:
panic("slice: bad open type");
}
break;
default:
panic("slice: bad request source");
}
/*
* Be appropriatly paranoid depending on the system mode.
* This is also probably wrong XXX
*/
switch(slicexclusive) {
case 2:
/*
* if any one path has it open, we forbid any other
* paths. Only allow an upgrade/downgrade from
* the same source as the present openner.
*/
if ( sl_flags & and_flags)
goto reject;
case 1: /*
* The behaviour is encoded into the state array given above.
*/
if ((or_flags & allowed[sl_flags]) != or_flags)
goto reject;
break;
case 0: /*
* Permission is granted to shoot self in foot.
* All three of UPPER, CHAR and BLK can be open at once.
*/
break;
}
/*
* Get the old open mode and the new open mode.
* If we already have it open in this way, don't do it again.
*
* XXX More thought needed for the locking and open-flags.
* For now ignore the existance of flags other than FWRITE & FREAD.
*/
odn_flags = (sl_flags & SLF_OPEN_WR) ? FWRITE : 0;
odn_flags |= (sl_flags & SLF_OPEN_RD) ? FREAD : 0;
sl_flags &= and_flags;
sl_flags |= or_flags;
dn_flags = (sl_flags & SLF_OPEN_WR) ? FWRITE : 0;
dn_flags |= (sl_flags & SLF_OPEN_RD) ? FREAD : 0;
error = 0;
if (dn_flags != odn_flags) {
if ((error = (*slice->handler_down->open) (slice->private_down,
dn_flags, mode, p)) != 0) {
goto reject;
}
}
slice->flags &= ~SLF_OPEN_STATE;
slice->flags |= sl_flags;
reject:
unlockslice(slice);
sl_unref(slice); /* lockslice gave us a ref.*/
return (error);
}
void
sliceclose(struct slice *slice, int flags, int mode,
struct proc * p, enum slc_who who)
{
sh_p tp;
if (slice->flags & SLF_INVALID)
return ;
if (lockslice(slice))
return ;
switch (who) {
case SLW_ABOVE:
slice->flags &= ~SLF_OPEN_UP;
break;
case SLW_DEVICE:
switch (mode & S_IFMT) {
case S_IFCHR:
slice->flags &= ~SLF_OPEN_CHR;
break;
case S_IFBLK:
slice->flags &= ~SLF_OPEN_BLK;
break;
default:
panic("slice: bad open type");
}
/*
* If we had an upper handler, ask it to check if it's still
* valid. it may decide to self destruct.
*/
if (slice->handler_up) {
(*slice->handler_up->verify)(slice);
}
/*
* If we don't have an upper handler, check if
* maybe there is now a suitable environment for one.
* We may end up with a different handler
* from what we had above. Maybe we should clear the hint?
* Maybe we should ask the lower one to re-issue the request?
*/
if (slice->handler_up == NULL) {
if ((tp = slice_probeall(slice)) != NULL) {
(*tp->constructor)(slice);
}
}
break;
}
/*
* Last-close semantics strike again
* This may refine to a downgrade if we closed (say) the last writer
* but there are still readers.
* probably open/close should merge to one 'mode-change' function.
* (except for a vnode reference with no mode)
*/
if ( (slice->flags & SLF_OPEN_STATE) == 0)
(*slice->handler_down->close) (slice->private_down,
flags, mode, p);
unlockslice(slice);
sl_unref(slice);
return ;
}
/*
* control behaviour of slices WRT sharing:
* 2 = no sharing
* 1 = read on a device already mounted (or parent of) is ok. No writes.
* 0 = go ahead.. shoot yourself in the foot.
*/
static int
sysctl_kern_slicexclusive SYSCTL_HANDLER_ARGS
{
int error;
int new_val = slicexclusive;
error = sysctl_handle_int(oidp, &new_val, 0, req);
if (error == 0) {
if ((new_val >= 0) && (new_val < 3)) {
slicexclusive = new_val;
} else {
error = EINVAL;
}
}
return (error);
}
SYSCTL_PROC(_kern, OID_AUTO, slicexclusive, CTLTYPE_INT|CTLFLAG_RW,
0, sizeof slicexclusive, sysctl_kern_slicexclusive, "I", "");