X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0b4e3aa066abc0728aacb4bbeb86f53f9737156e..43866e378188c25dd1e2208016ab3cbeb086ae6c:/bsd/vfs/vfs_subr.c diff --git a/bsd/vfs/vfs_subr.c b/bsd/vfs/vfs_subr.c index fd99cca8d..742af69fd 100644 --- a/bsd/vfs/vfs_subr.c +++ b/bsd/vfs/vfs_subr.c @@ -3,19 +3,22 @@ * * @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@ */ @@ -64,6 +67,7 @@ * External virtual filesystem routines */ +#undef DIAGNOSTIC #define DIAGNOSTIC 1 #include @@ -108,15 +112,6 @@ static int vnreclaim(int count); 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 */ @@ -260,7 +255,12 @@ __private_extern__ kern_return_t 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)); } @@ -635,6 +635,20 @@ insmntque(vp, mp) 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. */ @@ -642,19 +656,8 @@ void 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); } /* @@ -677,12 +680,22 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 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) && @@ -694,7 +707,7 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 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)) { @@ -720,7 +733,13 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) (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); } } @@ -730,82 +749,6 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) 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. @@ -934,6 +877,8 @@ vget(vp, flags, p) { 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 @@ -960,6 +905,19 @@ vget(vp, flags, p) 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 */ @@ -1462,9 +1420,9 @@ loop: 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; } @@ -1519,7 +1477,7 @@ loop: busy++; } simple_unlock(&mntvnode_slock); - if (busy) + if (busy && ((flags & FORCECLOSE)==0)) return (EBUSY); return (0); } @@ -1535,8 +1493,6 @@ vclean(vp, flags, p) struct proc *p; { int active; - void *obj; - kern_return_t kret; int removed = 0; int didhold; @@ -1936,6 +1892,8 @@ vprint(label, vp) 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) @@ -2000,10 +1958,19 @@ vfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 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)); } @@ -2358,12 +2325,10 @@ vm_object_cache_reclaim(int count) 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; @@ -2615,7 +2580,6 @@ int walk_vnodes_debug=0; void walk_allvnodes() { - struct proc *p = current_proc(); struct mount *mp, *nmp; struct vnode *vp; int cnt = 0;