mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-19 10:53:58 +00:00
26d3bf5f1b
Close is simply an open with no-read and no-write once internal to SLICE (it still exports a close to the rest of the kernel)
700 lines
20 KiB
C
700 lines
20 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: slice_base.c,v 1.2 1998/04/22 01:51:34 julian Exp $
|
|
*/
|
|
|
|
#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;
|
|
#if 1 /* it was basically a close */
|
|
if ((slice->flags & SLF_OPEN_STATE) == SLF_CLOSED) {
|
|
sh_p tp;
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
reject:
|
|
unlockslice(slice);
|
|
if ((slice->flags & SLF_INVALID) == SLF_INVALID)
|
|
error = ENODEV; /* we've been zapped while down there! */
|
|
sl_unref(slice); /* lockslice gave us a ref.*/
|
|
return (error);
|
|
}
|
|
|
|
#if 0
|
|
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 ;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
/*
|
|
* 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", "");
|
|
|