/*- * 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.5 1998/07/13 08:22:56 julian Exp $ */ #include #include #include /* SYSINIT stuff */ #include /* FREAD/FWRITE */ #include /* cdevsw stuff */ #include /* malloc region definitions */ #include /* buffers for IO */ #include /* linked lists etc. */ #include /* S_IFCHR, S_IFBLK */ #include /* the sysctl for shooting self in foot */ /*#include */ /* DEVFS defintitions */ #include /* temporary location */ #define SLICESPL() splbio() static void sl_async_done(struct buf *bp); 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); } /* * Make a handler instantiation of the requested type. * don't take no for an answer. * force it to mark it's new territory. * Must be called from a within a user context. * */ static int sl_make_handler(sl_p slice, char *type) { sh_p handler_up; /* * 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 */ slice->flags |= SLF_DONT_ARGUE; return( (*handler_up->claim) (slice)); } /* * lock and unlock Slices while doing operations such as open(). * gets a reference on the slice.. * XXX This doesn't work for SMP. */ int slice_lock(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, "slice_lock", 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 slice_unlock(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. * As of yet it has no upper handler. */ int sl_make_slice(sh_p handler_down, void *private_down, struct slicelimits * limits, sl_p * slicepp, 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; 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. * Should be called at SLICESPL (splbio) */ 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); } } /*********************************************************************** * Handler probing state machine support. ***********************************************************************/ /* * Ask all known handler types if a given slice is handled by them. * If the slice specifies a type, then just find that. * This will be done asynchronously. The claim operation may simply * queue the work to be done. When this item has been rejected, * control will pass to slice_probe_next(). * This starts up the generic probeing state machine, which * will start up the probing state machine for each handler in turn, * until one has claimed the device, or there are no more handlers. * */ void slice_start_probe(sl_p slice) { sh_p tp = types; if (slice->probeinfo.type == NULL) { if(slice->handler_up == NULL) { slice->probeinfo.trial_handler = tp; slice->flags |= SLF_PROBING; printf("%s: probing for %s.. ",slice->name, tp->name); (*tp->claim) (slice); } return; } /* * Null string ("") means "don't even try". Caller probably * should pre-trap such cases but we'll check here too. * Notice that the PROBING bit is not set. * This means that we should not do a full probe, * but just this one handler. */ if (slice->probeinfo.type[0]) { tp = sl_findtype(slice->probeinfo.type); if (tp) { printf("%s: attaching %s..\n", slice->name, tp->name); (*tp->claim) (slice); } } } /* * Move the slice probe type, on to the next type * and call that. Called from failed probes. * Don't do anything if the PROBING flag has been cleared. */ void slice_probe_next(sl_p slice) { sh_p tp = slice->probeinfo.trial_handler; if ((slice->flags & SLF_PROBING) == 0) return; if (tp != NULL) { if (slice->probeinfo.trial_handler = tp = tp->next) { printf("%s: probing for %s.. ",slice->name, tp->name); (*tp->claim) (slice); return; } } slice->flags &= ~SLF_PROBING; } /* * Given a slice, launch an IOrequest for information * This is not a bulk IO routine but meant for probes etc. * This routine may be called at interrupt time. It schedules an * IO that will be completed asynchronously. On completion the * Block IO system will call sl_async_done, which will trigger * a completion event for the handler's probe state machine. */ int slice_request_block(sl_p slice, int blknum) { struct buf *bp; int s; RR; s = splbio(); #ifdef PARANOID if ( slice->private_up == NULL) { panic("slice_request_block: no pd"); } if (slice->flags & SLF_PROBE_STATE) { panic("slice_request_block: 2nd IO"); } #endif /* PARANOID */ bp = geteblk((int) slice->limits.blksize); if (bp == NULL) { return (ENOMEM); } slice->flags |= SLF_WAIT_READ; bp->b_iodone = &sl_async_done; bp->b_flags |= B_CALL; bp->b_dev = (dev_t)slice; /* XXX HACK ALERT! */ bp->b_pblkno = bp->b_blkno = blknum; bp->b_bcount = slice->limits.blksize; bp->b_flags |= B_BUSY | B_READ; sliceio(slice, bp, SLW_ABOVE); splx(s); return (0); } /* * Write 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?) no, they may block? */ int slice_writeblock(struct slice * slice, int blkno, void (*iodone )(struct buf *), caddr_t data, int len) { struct buf *bp; int error = 0; #ifdef PARANOID if ( slice->handler_up == NULL) { panic("slice_writeblock: no handler"); } if (slice->flags & SLF_PROBE_STATE) { panic("slice_writeblock: 2nd IO"); } #endif /* PARANOID */ if (len > slice->limits.blksize) return (EINVAL); bp = geteblk((int) slice->limits.blksize); if (bp == NULL) { return (ENOMEM); } slice->flags |= SLF_WAIT_WRITE; bcopy(data, bp->b_data, len); bp->b_iodone = sl_async_done; bp->b_flags |= B_CALL; bp->b_dev = (dev_t)slice; /* XXX HACK ALERT! */ 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); return (0); } /* * called with an argument of a bp when it is completed. * Th eslice is extracted from the operation and the completion event * is used to trigger that slice's state machine to make the next move. */ static void sl_async_done(struct buf *bp) { sl_p slice; int error; RR; if (bp->b_dev < 0xf0000000) panic ("b_dev used in SLICE code"); slice = (struct slice *)bp->b_dev; /* XXX HACK! */ #ifdef PARANOID if ( slice->handler_up == NULL) { panic("sl_async_done: no pd"); } if (bp->b_flags & B_READ) { if ((slice->flags & SLF_PROBE_STATE) != SLF_WAIT_READ) panic("sl_async_done: unexpected read completion"); } else { if ((slice->flags & SLF_PROBE_STATE) != SLF_WAIT_WRITE) panic("sl_async_done: unexpected write completion"); } #endif /* PARANOID */ /* * if the IO failed, then abandon the probes and * return. Possibly ask the lower layer to try again later? * It's assumed that a a revoke will abort the state machine. * XXX Maybe we should call the done() routine anyhow * and let each handler detect the failure.. */ if (bp->b_flags & B_ERROR) { (* slice->handler_up->revoke)(slice->private_up); /* (* slice->handler_down->SOMETHING) (slice->private_down); */ bp->b_flags |= B_INVAL | B_AGE; brelse(bp); slice->flags &= ~SLF_PROBING; return; } /* * Call the handler's done() routine. This will * examine the result of the probe and do whatever is needed. * Check for abnormal error conditions. (return value non 0) * Not claiming the slice is not an error condition. */ if ( (* slice->handler_up->done)(slice, bp)) { slice->flags &= ~SLF_PROBING; return; } /* * If the handler has left itself there, or cleared * the PROBING bit, then consider * probing to have come to a close. So just return. * XXX An IO error would be a great hint to abandon probing as well. * we catch that on the way up but we might want to give * the handler a chance to clean up state? */ if (slice->handler_up || ((slice->flags & SLF_PROBING) == 0)) { slice->flags &= ~SLF_PROBING; return; } /* * The handler didn't claim it. Nor did it abort the * probing sequence. * Ok, so we should try the next handler to probe. */ slice_probe_next(slice); } /* * 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 = slice_lock(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"); } /* XXX only accumulate flags as we don't know about all closes */ /* XXX */ if ( or_flags ) /* XXX */ and_flags = ~0; 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) { slice_start_probe(slice); } } #endif reject: slice_unlock(slice); if ((slice->flags & SLF_INVALID) == SLF_INVALID) error = ENODEV; /* we've been zapped while down there! */ sl_unref(slice); /* slice_lock 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 (slice_lock(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_start_probe(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); slice_unlock(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", "");