]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/vfs_subr.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_subr.c
index fd99cca8d7b2bd369a04235d49524ea7330f2601..742af69fd44626bc2368ebc33679018898f2ff49 100644 (file)
@@ -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 <sys/param.h>
@@ -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;