summaryrefslogtreecommitdiffstats
path: root/sys/dev/slice/slice_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/slice/slice_base.c')
-rw-r--r--sys/dev/slice/slice_base.c671
1 files changed, 671 insertions, 0 deletions
diff --git a/sys/dev/slice/slice_base.c b/sys/dev/slice/slice_base.c
new file mode 100644
index 0000000..558720b
--- /dev/null
+++ b/sys/dev/slice/slice_base.c
@@ -0,0 +1,671 @@
+/*-
+ * 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", "");
+
OpenPOWER on IntegriCloud