*
* @APPLE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
* External virtual filesystem routines
*/
+#undef DIAGNOSTIC
#define DIAGNOSTIC 1
#include <sys/param.h>
extern kern_return_t
adjust_vm_object_cache(vm_size_t oval, vm_size_t nval);
-/*
- * Insq/Remq for the vnode usage lists.
- */
-#define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs)
-#define bufremvn(bp) { \
- LIST_REMOVE(bp, b_vnbufs); \
- (bp)->b_vnbufs.le_next = NOLIST; \
-}
-
TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */
TAILQ_HEAD(inactivelst, vnode) vnode_inactive_list; /* vnode inactive list */
struct mntlist mountlist; /* mounted filesystem list */
reset_vmobjectcache(unsigned int val1, unsigned int val2)
{
vm_size_t oval = val1 - VNODE_FREE_MIN;
- vm_size_t nval = val2 - VNODE_FREE_MIN;
+ vm_size_t nval;
+
+ if(val2 < VNODE_FREE_MIN)
+ nval = 0;
+ else
+ nval = val2 - VNODE_FREE_MIN;
return(adjust_vm_object_cache(oval, nval));
}
simple_unlock(&mntvnode_slock);
}
+__inline void
+vpwakeup(struct vnode *vp)
+{
+ if (vp) {
+ if (--vp->v_numoutput < 0)
+ panic("vpwakeup: neg numoutput");
+ if ((vp->v_flag & VBWAIT || vp->v_flag & VTHROTTLED)
+ && vp->v_numoutput <= 0) {
+ vp->v_flag &= ~(VBWAIT|VTHROTTLED);
+ wakeup((caddr_t)&vp->v_numoutput);
+ }
+ }
+}
+
/*
* Update outstanding I/O count and do wakeup if requested.
*/
vwakeup(bp)
register struct buf *bp;
{
- register struct vnode *vp;
-
CLR(bp->b_flags, B_WRITEINPROG);
- if (vp = bp->b_vp) {
- if (--vp->v_numoutput < 0)
- panic("vwakeup: neg numoutput");
- if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
- if (vp->v_numoutput < 0)
- panic("vwakeup: neg numoutput 2");
- vp->v_flag &= ~VBWAIT;
- wakeup((caddr_t)&vp->v_numoutput);
- }
- }
+ vpwakeup(bp->b_vp);
}
/*
if (error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) {
return (error);
}
- if (vp->v_dirtyblkhd.lh_first != NULL || (vp->v_flag & VHASDIRTY))
- panic("vinvalbuf: dirty bufs");
+
+ // XXXdbg - if there are dirty bufs, wait for 'em if they're busy
+ for (bp=vp->v_dirtyblkhd.lh_first; bp; bp=nbp) {
+ nbp = bp->b_vnbufs.le_next;
+ if (ISSET(bp->b_flags, B_BUSY)) {
+ SET(bp->b_flags, B_WANTED);
+ tsleep((caddr_t)bp, slpflag | (PRIBIO + 1), "vinvalbuf", 0);
+ nbp = vp->v_dirtyblkhd.lh_first;
+ } else {
+ panic("vinvalbuf: dirty buf (vp 0x%x, bp 0x%x)", vp, bp);
+ }
+ }
}
for (;;) {
- if ((blist = vp->v_cleanblkhd.lh_first) && flags & V_SAVEMETA)
+ if ((blist = vp->v_cleanblkhd.lh_first) && (flags & V_SAVEMETA))
while (blist && blist->b_lblkno < 0)
blist = blist->b_vnbufs.le_next;
if (!blist && (blist = vp->v_dirtyblkhd.lh_first) &&
for (bp = blist; bp; bp = nbp) {
nbp = bp->b_vnbufs.le_next;
- if (flags & V_SAVEMETA && bp->b_lblkno < 0)
+ if ((flags & V_SAVEMETA) && bp->b_lblkno < 0)
continue;
s = splbio();
if (ISSET(bp->b_flags, B_BUSY)) {
(void) VOP_BWRITE(bp);
break;
}
- SET(bp->b_flags, B_INVAL);
+
+ if (bp->b_flags & B_LOCKED) {
+ panic("vinvalbuf: bp @ 0x%x is locked!\n", bp);
+ break;
+ } else {
+ SET(bp->b_flags, B_INVAL);
+ }
brelse(bp);
}
}
return (0);
}
-/*
- * Associate a buffer with a vnode.
- */
-void
-bgetvp(vp, bp)
- register struct vnode *vp;
- register struct buf *bp;
-{
-
- if (bp->b_vp)
- panic("bgetvp: not free");
- VHOLD(vp);
- bp->b_vp = vp;
- if (vp->v_type == VBLK || vp->v_type == VCHR)
- bp->b_dev = vp->v_rdev;
- else
- bp->b_dev = NODEV;
- /*
- * Insert onto list for new vnode.
- */
- bufinsvn(bp, &vp->v_cleanblkhd);
-}
-
-/*
- * Disassociate a buffer from a vnode.
- */
-void
-brelvp(bp)
- register struct buf *bp;
-{
- struct vnode *vp;
-
- if (bp->b_vp == (struct vnode *) 0)
- panic("brelvp: NULL");
- /*
- * Delete from old vnode list, if on one.
- */
- if (bp->b_vnbufs.le_next != NOLIST)
- bufremvn(bp);
- vp = bp->b_vp;
- bp->b_vp = (struct vnode *) 0;
- HOLDRELE(vp);
-}
-
-/*
- * Reassign a buffer from one vnode to another.
- * Used to assign file specific control information
- * (indirect blocks) to the vnode to which they belong.
- */
-void
-reassignbuf(bp, newvp)
- register struct buf *bp;
- register struct vnode *newvp;
-{
- register struct buflists *listheadp;
-
- if (newvp == NULL) {
- printf("reassignbuf: NULL");
- return;
- }
- /*
- * Delete from old vnode list, if on one.
- */
- if (bp->b_vnbufs.le_next != NOLIST)
- bufremvn(bp);
- /*
- * If dirty, put on list of dirty buffers;
- * otherwise insert onto list of clean buffers.
- */
- if (ISSET(bp->b_flags, B_DELWRI))
- listheadp = &newvp->v_dirtyblkhd;
- else
- listheadp = &newvp->v_cleanblkhd;
- bufinsvn(bp, listheadp);
-}
-
/*
* Create a vnode for a block device.
* Used for root filesystem, argdev, and swap areas.
{
int error = 0;
+retry:
+
/*
* If the vnode is in the process of being cleaned out for
* another use, we wait for the cleaning to finish and then
return (ENOENT);
}
+ /*
+ * if the vnode is being initialized,
+ * wait for it to finish initialization
+ */
+ if (ISSET(vp->v_flag, VUINIT)) {
+ if (ISSET(vp->v_flag, VUINIT)) {
+ SET(vp->v_flag, VUWANT);
+ simple_unlock(&vp->v_interlock);
+ (void) tsleep((caddr_t)vp, PINOD, "vget2", 0);
+ goto retry;
+ }
+ }
+
simple_lock(&vnode_free_list_slock);
if (vp->v_usecount == 0) {
/* If on the free list, remove it from there */
simple_lock(&vp->v_interlock);
/*
- * Skip over a vnodes marked VSYSTEM.
+ * Skip over a vnodes marked VSYSTEM or VNOFLUSH.
*/
- if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) {
+ if ((flags & SKIPSYSTEM) && ((vp->v_flag & VSYSTEM) || (vp->v_flag & VNOFLUSH))) {
simple_unlock(&vp->v_interlock);
continue;
}
busy++;
}
simple_unlock(&mntvnode_slock);
- if (busy)
+ if (busy && ((flags & FORCECLOSE)==0))
return (EBUSY);
return (0);
}
struct proc *p;
{
int active;
- void *obj;
- kern_return_t kret;
int removed = 0;
int didhold;
strcat(buf, "|VTEXT");
if (vp->v_flag & VSYSTEM)
strcat(buf, "|VSYSTEM");
+ if (vp->v_flag & VNOFLUSH)
+ strcat(buf, "|VNOFLUSH");
if (vp->v_flag & VXLOCK)
strcat(buf, "|VXLOCK");
if (vp->v_flag & VXWANT)
size_t newlen;
struct proc *p;
{
- struct ctldebug *cdp;
struct vfsconf *vfsp;
- if (name[0] == VFS_NUMMNTOPS) {
+ /*
+ * The VFS_NUMMNTOPS shouldn't be at name[0] since
+ * is a VFS generic variable. So now we must check
+ * namelen so we don't end up covering any UFS
+ * variables (sinc UFS vfc_typenum is 1).
+ *
+ * It should have been:
+ * name[0]: VFS_GENERIC
+ * name[1]: VFS_NUMMNTOPS
+ */
+ if (namelen == 1 && name[0] == VFS_NUMMNTOPS) {
extern unsigned int vfs_nummntops;
return (sysctl_rdint(oldp, oldlenp, newp, vfs_nummntops));
}
static int
vnreclaim(int count)
{
- int cnt, i, loopcnt;
- void *obj;
+ int i, loopcnt;
struct vnode *vp;
int err;
struct proc *p;
- kern_return_t kret;
i = 0;
loopcnt = 0;
void
walk_allvnodes()
{
- struct proc *p = current_proc();
struct mount *mp, *nmp;
struct vnode *vp;
int cnt = 0;