diff options
Diffstat (limited to 'sys/dev/slice/slice_base.c')
-rw-r--r-- | sys/dev/slice/slice_base.c | 671 |
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", ""); + |