]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/miscfs/union/union_vnops.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / miscfs / union / union_vnops.c
index 4b1ca8ef199697d34d11fab6016e05f634a0fe3c..240ab9f40547d369c350e3cd1bf7fbe4d64a0561 100644 (file)
@@ -1,23 +1,29 @@
 /*
  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_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.
+ * 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. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
 /*
 #include <miscfs/union/union.h>
 #include <vfs/vfs_support.h>
 #include <sys/ubc.h>
+#include <sys/kdebug.h>
 #include <sys/uio_internal.h>
 
-#define FIXUP(un, p) { \
-       if (((un)->un_flags & UN_ULOCK) == 0) { \
-               union_fixup(un, p); \
-       } \
-}
-
-static void
-union_fixup(un, p)
-       struct union_node *un;
-       struct proc *p;
-{
-
-       un->un_flags |= UN_ULOCK;
-}
-
+/* called with no union lock held */
 static int
 union_lookup1(struct vnode *udvp, struct vnode **dvpp, struct vnode **vpp,
        struct componentname *cnp)
@@ -158,30 +151,35 @@ union_lookup1(struct vnode *udvp, struct vnode **dvpp, struct vnode **vpp,
        return (0);
 }
 
-int
-union_lookup(
-       struct vnop_lookup_args /* {
+static int
+union_lookup(struct vnop_lookup_args *ap)
+/*
+       struct vnop_lookup_args {
                struct vnodeop_desc *a_desc;
                struct vnode *a_dvp;
                struct vnode **a_vpp;
                struct componentname *a_cnp;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap)
+*/
 {
        int error;
-       int uerror, lerror;
+       int uerror = 0;
+       int  lerror = 0;
        struct vnode *uppervp, *lowervp;
        struct vnode *upperdvp, *lowerdvp;
        struct vnode *dvp = ap->a_dvp;
-       struct union_node *dun = VTOUNION(dvp);
+       struct union_node *dun;
        struct componentname *cnp = ap->a_cnp;
        vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
        int lockparent = cnp->cn_flags & LOCKPARENT;
-       struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
+       struct union_mount *um;
        kauth_cred_t saved_cred;
        int iswhiteout;
        struct vnode_attr va;
+       int isfaultfs = 0;
+       int upperlookup = 0;
+       int retry_count = 0;
 
 #ifdef notyet
        if (cnp->cn_namelen == 3 &&
@@ -197,14 +195,26 @@ union_lookup(
        }
 #endif
 
-       cnp->cn_flags |= LOCKPARENT;
+       
 
+retry:
+       union_lock();
+       um = MOUNTTOUNIONMOUNT(dvp->v_mount);
+       dun = VTOUNION(dvp);
        upperdvp = dun->un_uppervp;
        lowerdvp = dun->un_lowervp;
        uppervp = NULLVP;
        lowervp = NULLVP;
        iswhiteout = 0;
 
+       union_unlock();
+
+       if(UNION_FAULTIN(um))
+               isfaultfs = 1;
+
+       if (isfaultfs == 0)
+               cnp->cn_flags |= LOCKPARENT;
+
        /*
         * do the lookup in the upper level.
         * if that level comsumes additional pathnames,
@@ -212,16 +222,18 @@ union_lookup(
         * on and just return that vnode.
         */
        if (upperdvp != NULLVP) {
-               FIXUP(dun, p);
+               if (lockparent != 0) 
+                       cnp->cn_flags &= ~LOCKPARENT;
                uerror = union_lookup1(um->um_uppervp, &upperdvp,
                                        &uppervp, cnp);
-               /*if (uppervp == upperdvp)
-                       dun->un_flags |= UN_KLOCK;*/
+               upperlookup = 1;
 
                if (cnp->cn_consume != 0) {
                        *ap->a_vpp = uppervp;
                        if (!lockparent)
                                cnp->cn_flags &= ~LOCKPARENT;
+                       else
+                               cnp->cn_flags |= LOCKPARENT;    
                        return (uerror);
                }
                if (uerror == ENOENT || uerror == EJUSTRETURN) {
@@ -239,6 +251,15 @@ union_lookup(
                uerror = ENOENT;
        }
 
+       /*
+        * faultingfs: If upper layer lookup is succesful
+        * we will return that vp if it is regular file.
+        * So so skip lower level lookup
+        */
+
+       if ((isfaultfs == 1) && (upperlookup == 1) && (uerror == 0) && ((vnode_isreg(uppervp) != 0)))
+               goto donelowerlookup;
+
        /*
         * in a similar way to the upper layer, do the lookup
         * in the lower layer.   this time, if there is some
@@ -259,10 +280,14 @@ union_lookup(
                        /* XXX BOGUS */
                        saved_cred = cnp->cn_context->vc_ucred;
                        cnp->cn_context->vc_ucred = um->um_cred;
+                       if (lockparent != 0) 
+                               cnp->cn_flags &= ~LOCKPARENT;
                        lerror = union_lookup1(um->um_lowervp, &lowerdvp,
                                        &lowervp, cnp);
                        cnp->cn_context->vc_ucred = saved_cred;
                } else {
+                       if (lockparent != 0) 
+                               cnp->cn_flags &= ~LOCKPARENT;
                        lerror = union_lookup1(um->um_lowervp, &lowerdvp,
                                        &lowervp, cnp);
                }
@@ -276,6 +301,8 @@ union_lookup(
                        *ap->a_vpp = lowervp;
                        if (!lockparent)
                                cnp->cn_flags &= ~LOCKPARENT;
+                       else
+                               cnp->cn_flags |= LOCKPARENT;    
                        return (lerror);
                }
        } else {
@@ -283,12 +310,13 @@ union_lookup(
                if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
                        lowervp = LOWERVP(dun->un_pvp);
                        if (lowervp != NULLVP) {
-                               vnode_get(lowervp);
                                lerror = 0;
                        }
                }
        }
 
+donelowerlookup:
+
        if (!lockparent)
                cnp->cn_flags &= ~LOCKPARENT;
 
@@ -320,27 +348,72 @@ union_lookup(
 
        /* case 1. */
        if ((uerror != 0) && (lerror != 0)) {
+                       if (!lockparent)
+                               cnp->cn_flags &= ~LOCKPARENT;
+                       else
+                               cnp->cn_flags |= LOCKPARENT;    
                return (uerror);
        }
 
        /* case 2. */
        if (uerror != 0 /* && (lerror == 0) */ ) {
                if (lowervp->v_type == VDIR) { /* case 2b. */
-                       dun->un_flags &= ~UN_ULOCK;
+                       /* No need to lock the union here */
+                       /* if the vnode exists it returns it even if it marks error */
+
+                       uppervp = NULLVP;
+
                        uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
-                       dun->un_flags |= UN_ULOCK;
 
+                       if ((uerror == EEXIST)){
+                               if (uppervp == NULLVP) {
+                                       retry_count++;
+                                       if (retry_count <= 2) {
+                                               if (lowervp != NULLVP) 
+                                                       vnode_put(lowervp);
+                                               goto retry;
+                                       }
+                               }
+                               uerror = 0;
+                       }
+                       
                        if (uerror) {
+                               if (uppervp != NULLVP) {
+                                       vnode_put(uppervp);
+                               }
                                if (lowervp != NULLVP) {
                                        vnode_put(lowervp);
-                                       lowervp = NULLVP;
                                }
+                               if (!lockparent)
+                                       cnp->cn_flags &= ~LOCKPARENT;
+                               else
+                                       cnp->cn_flags |= LOCKPARENT;    
                                return (uerror);
                        }
+               } else if ((lowervp->v_type == VREG) && (isfaultfs == 1)) {
+                       error = union_faultin_copyup(&uppervp, upperdvp, lowervp, cnp, ctx);    
+                       uerror = 0;
                }
        }
+
+
+       /* if this is faulting filesystem and upper vp exisits skip allocation of union node */
+       if ((isfaultfs == 1) && (uerror == 0) && (uppervp != NULLVP) &&  ((vnode_isreg(uppervp) != 0)|| (vnode_islnk(uppervp) != 0))) {
+               vn_checkunionwait(uppervp);
+               *ap->a_vpp = uppervp;
+               if (lowervp != NULLVP)
+                       vnode_put(lowervp);
+               if (!lockparent)
+                       cnp->cn_flags &= ~LOCKPARENT;
+               else
+                       cnp->cn_flags |= LOCKPARENT;    
+               return(0);
+       }
+
+       union_lock();
        error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
                              uppervp, lowervp, 1);
+       union_unlock();
 
        if (error) {
                if (uppervp != NULLVP)
@@ -349,33 +422,35 @@ union_lookup(
                        vnode_put(lowervp);
        }
 
+       if (!lockparent)
+               cnp->cn_flags &= ~LOCKPARENT;
+       else
+               cnp->cn_flags |= LOCKPARENT;    
        return (error);
 }
 
-int
-union_create(
-       struct vnop_create_args /* {
+static int
+union_create(struct vnop_create_args *ap)
+/*
+       struct vnop_create_args {
                struct vnode *a_dvp;
                struct vnode **a_vpp;
                struct componentname *a_cnp;
                struct vnode_attr *a_vap;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_dvp);
        struct vnode *dvp = un->un_uppervp;
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
 
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
                struct mount *mp;
 
-               FIXUP(un, p);
 
-               un->un_flags |= UN_KLOCK;
                mp = ap->a_dvp->v_mount;
 
                /* note that this is a direct passthrough to the filesystem */
@@ -383,60 +458,71 @@ union_create(
                if (error)
                        return (error);
 
+               /* if this is faulting filesystem and is a reg file, skip allocation of union node */
+               if (UNNODE_FAULTIN(un) && (vp != NULLVP) && ((vnode_isreg(vp) != 0)|| (vnode_islnk(vp) != 0))) {
+                       *ap->a_vpp = vp;
+                       return(0);
+               }
+
+
+               union_lock();
                error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp,
                                NULLVP, 1);
+               union_unlock();
                if (error)
                        vnode_put(vp);
                return (error);
        }
+
        return (EROFS);
 }
 
-int
-union_whiteout(
-       struct vnop_whiteout_args /* {
+static int
+union_whiteout(struct vnop_whiteout_args *ap)
+/*
+       struct vnop_whiteout_args {
                struct vnode *a_dvp;
                struct componentname *a_cnp;
                int a_flags;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_dvp);
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
+       int error;
 
-       if (un->un_uppervp == NULLVP)
+       if (un->un_uppervp == NULLVP) {
                return (ENOTSUP);
+       }
 
-       FIXUP(un, p);
-       return (VNOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags, ap->a_context));
+       error =  (VNOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags, ap->a_context));
+       return(error);
 }
 
-int
-union_mknod(
-       struct vnop_mknod_args /* {
+/* mknod can do  fifos, chr, blk or whiteout entries */
+static int
+union_mknod(struct vnop_mknod_args *ap)
+/*
+       struct vnop_mknod_args {
                struct vnode *a_dvp;
                struct vnode **a_vpp;
                struct componentname *a_cnp;
                struct vnode_attr *a_vap;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_dvp);
        struct vnode *dvp = un->un_uppervp;
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
 
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
                struct mount *mp;
 
-               FIXUP(un, p);
 
-               un->un_flags |= UN_KLOCK;
                mp = ap->a_dvp->v_mount;
 
                /* note that this is a direct passthrough to the filesystem */
@@ -445,8 +531,10 @@ union_mknod(
                        return (error);
 
                if (vp != NULLVP) {
+                       union_lock();
                        error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
                                        cnp, vp, NULLVP, 1);
+                       union_unlock();
                        if (error)
                                vnode_put(vp);
                }
@@ -455,27 +543,29 @@ union_mknod(
        return (EROFS);
 }
 
-int
-union_open(
-       struct vnop_open_args /* {
+static int
+union_open(struct vnop_open_args *ap)
+/*
+       struct vnop_open_args {
                struct vnodeop_desc *a_desc;
                struct vnode *a_vp;
                int a_mode;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_vp);
        struct vnode *tvp;
        int mode = ap->a_mode;
-       kauth_cred_t cred = vfs_context_ucred(ap->a_context);
-       struct proc *p = vfs_context_proc(ap->a_context);
        int error;
 
        /*
         * If there is an existing upper vp then simply open that.
         */
+
        tvp = un->un_uppervp;
        if (tvp == NULLVP) {
+
                /*
                 * If the lower vnode is being opened for writing, then
                 * copy the file contents to the upper vnode and open that,
@@ -483,7 +573,19 @@ union_open(
                 */
                tvp = un->un_lowervp;
                if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
-                       error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
+                       /* For above below mounts we need draining.. */
+                       /* This path is not taken for faultin mode */
+                       /*  LOCK the union node as well **/
+                       union_lock();
+                       un->un_flags |= UN_LOCKED;
+
+                       error = union_copyup(un, (mode&O_TRUNC) == 0, ap->a_context);
+                       un->un_flags &= ~UN_LOCKED;
+                       if ((un->un_flags & UN_WANT) == UN_WANT) {
+                               un->un_flags &=  ~UN_WANT;
+                               wakeup(&un->un_flags);
+                       }
+                       union_unlock();
                        if (error == 0)
                                error = VNOP_OPEN(un->un_uppervp, mode, ap->a_context);
                        return (error);
@@ -499,23 +601,24 @@ union_open(
                return (error);
        }
 
-       FIXUP(un, p);
-
        error = VNOP_OPEN(tvp, mode, ap->a_context);
 
        return (error);
 }
 
-int
-union_close(ap)
-       struct vnop_close_args /* {
+static int
+union_close(struct vnop_close_args *ap)
+/*
+       struct vnop_close_args {
                struct vnode *a_vp;
                int  a_fflag;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_vp);
        struct vnode *vp;
+       int error = 0;
 
        if ((vp = un->un_uppervp) == NULLVP) {
 #ifdef UNION_DIAGNOSTIC
@@ -527,7 +630,8 @@ union_close(ap)
        }
 
        ap->a_vp = vp;
-       return (VCALL(vp, VOFFSET(vnop_close), ap));
+       error =  (VCALL(vp, VOFFSET(vnop_close), ap));
+       return(error);
 }
 
 /*
@@ -538,22 +642,22 @@ union_close(ap)
  * file permissions are given away simply because
  * the user caused an implicit file copy.
  */
-int
-union_access(
-       struct vnop_access_args /* {
+static int
+union_access(struct vnop_access_args *ap)
+/*
+       struct vnop_access_args {
                struct vnodeop_desc *a_desc;
                struct vnode *a_vp;
                int a_action;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_vp);
-       struct proc *p = vfs_context_proc(ap->a_context);
        int error = EACCES;
        struct vnode *vp;
 
        if ((vp = un->un_uppervp) != NULLVP) {
-               FIXUP(un, p);
                ap->a_vp = vp;
                return (VCALL(vp, VOFFSET(vnop_access), ap));
        }
@@ -565,8 +669,6 @@ union_access(
                        struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
 
                        if (um->um_op == UNMNT_BELOW) {
-                               /* XXX fix me */
-                       //      ap->a_cred = um->um_cred;
                                error = VCALL(vp, VOFFSET(vnop_access), ap);
                        }
                }
@@ -581,18 +683,19 @@ union_access(
  * We handle getattr only to change the fsid and
  * track object sizes
  */
-int
-union_getattr(ap)
-       struct vnop_getattr_args /* {
+static int
+union_getattr(struct vnop_getattr_args *ap)
+/*
+       struct vnop_getattr_args {
                struct vnode *a_vp;
                struct vnode_attr *a_vap;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
-       int error;
+       int error=0;
        struct union_node *un = VTOUNION(ap->a_vp);
        struct vnode *vp = un->un_uppervp;
-       struct proc *p = vfs_context_proc(ap->a_context);
        struct vnode_attr *vap;
        struct vnode_attr va;
 
@@ -618,13 +721,14 @@ union_getattr(ap)
                 * In the mean time, compensate here by checking
                 * the union_node's lock flag.
                 */
-               if (un->un_flags & UN_LOCKED)
-                       FIXUP(un, p);
 
                error = vnode_getattr(vp, vap, ap->a_context);
-               if (error)
+               if (error) {
                        return (error);
+               }
+               union_lock();
                union_newsize(ap->a_vp, vap->va_data_size, VNOVAL);
+               union_unlock();
        }
 
        if (vp == NULLVP) {
@@ -641,9 +745,12 @@ union_getattr(ap)
 
        if (vp != NULLVP) {
                error = vnode_getattr(vp, vap, ap->a_context);
-               if (error)
+               if (error) {
                        return (error);
+               }
+               union_lock();
                union_newsize(ap->a_vp, VNOVAL, vap->va_data_size);
+               union_unlock();
        }
 
        if ((vap != ap->a_vap) && (vap->va_type == VDIR))
@@ -653,17 +760,17 @@ union_getattr(ap)
        return (0);
 }
 
-int
-union_setattr(ap)
-       struct vnop_setattr_args /* {
+static int
+union_setattr(struct vnop_setattr_args *ap)
+/*
+       struct vnop_setattr_args {
                struct vnode *a_vp;
                struct vnode_attr *a_vap;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_vp);
-       struct proc *p = vfs_context_proc(ap->a_context);
-       kauth_cred_t cred = vfs_context_ucred(ap->a_context);
        int error;
 
        /*
@@ -675,9 +782,12 @@ union_setattr(ap)
            (un->un_uppervp == NULLVP) &&
            /* assert(un->un_lowervp != NULLVP) */
            (un->un_lowervp->v_type == VREG)) {
-               error = union_copyup(un, (ap->a_vap->va_data_size != 0), cred, p);
-               if (error)
+               union_lock();
+               error = union_copyup(un, (ap->a_vap->va_data_size != 0), ap->a_context);
+               union_unlock();
+               if (error) {
                        return (error);
+               }
        }
 
        /*
@@ -685,10 +795,12 @@ union_setattr(ap)
         * otherwise return read-only filesystem error.
         */
        if (un->un_uppervp != NULLVP) {
-               FIXUP(un, p);
                error = vnode_setattr(un->un_uppervp, ap->a_vap, ap->a_context);
-               if ((error == 0) && VATTR_IS_ACTIVE(ap->a_vap, va_data_size))
+               if ((error == 0) && VATTR_IS_ACTIVE(ap->a_vap, va_data_size)) {
+                       union_lock();
                        union_newsize(ap->a_vp, ap->a_vap->va_data_size, VNOVAL);
+                       union_unlock();
+               }
        } else {
                error = EROFS;
        }
@@ -696,22 +808,20 @@ union_setattr(ap)
        return (error);
 }
 
-int
-union_read(ap)
-       struct vnop_read_args /* {
+static int
+union_read(struct vnop_read_args *ap)
+/*
+       struct vnop_read_args {
                struct vnode *a_vp;
                struct uio *a_uio;
                int  a_ioflag;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
-       struct proc *p = vfs_context_proc(ap->a_context);
        struct vnode *vp = OTHERVP(ap->a_vp);
-       int dolock = (vp == LOWERVP(ap->a_vp));
 
-       if (!dolock)
-               FIXUP(VTOUNION(ap->a_vp), p);
        error = VNOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_context);
 
        /*
@@ -725,36 +835,42 @@ union_read(ap)
                off_t cur = ap->a_uio->uio_offset;
 
                if (vp == un->un_uppervp) {
-                       if (cur > un->un_uppersz)
+                       if (cur > un->un_uppersz) {
+                               union_lock();
                                union_newsize(ap->a_vp, cur, VNOVAL);
+                               union_unlock();
+                       }
                } else {
-                       if (cur > un->un_lowersz)
+                       if (cur > un->un_lowersz) {
+                               union_lock();
                                union_newsize(ap->a_vp, VNOVAL, cur);
+                               union_unlock();
+                       }
                }
        }
 
        return (error);
 }
 
-int
-union_write(ap)
-       struct vnop_read_args /* {
+static int
+union_write(struct vnop_write_args *ap)
+/*
+       struct vnop_write_args {
                struct vnode *a_vp;
                struct uio *a_uio;
                int  a_ioflag;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
        struct vnode *vp;
        struct union_node *un = VTOUNION(ap->a_vp);
-       struct proc *p = vfs_context_proc(ap->a_context);
 
        vp = UPPERVP(ap->a_vp);
        if (vp == NULLVP)
                panic("union: missing upper layer in write");
 
-       FIXUP(un, p);
        error = VNOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_context);
 
        /*
@@ -764,23 +880,28 @@ union_write(ap)
        if (error == 0) {
                off_t cur = ap->a_uio->uio_offset;
 
-               if (cur > un->un_uppersz)
+               if (cur > un->un_uppersz) {
+                       union_lock();
                        union_newsize(ap->a_vp, cur, VNOVAL);
+                       union_unlock();
+               }
        }
 
        return (error);
 }
 
 
-int
-union_ioctl(ap)
-       struct vnop_ioctl_args /* {
+static int
+union_ioctl(struct vnop_ioctl_args *ap)
+/*
+       struct vnop_ioctl_args {
                struct vnode *a_vp;
                int  a_command;
                caddr_t  a_data;
                int  a_fflag;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        register struct vnode *ovp = OTHERVP(ap->a_vp);
 
@@ -788,15 +909,17 @@ union_ioctl(ap)
        return (VCALL(ovp, VOFFSET(vnop_ioctl), ap));
 }
 
-int
-union_select(ap)
-       struct vnop_select_args /* {
+static int
+union_select(struct vnop_select_args *ap)
+/*
+       struct vnop_select_args {
                struct vnode *a_vp;
                int  a_which;
                int  a_fflags;
                void * a_wql;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        register struct vnode *ovp = OTHERVP(ap->a_vp);
 
@@ -804,13 +927,15 @@ union_select(ap)
        return (VCALL(ovp, VOFFSET(vnop_select), ap));
 }
 
-int
-union_revoke(ap)
-       struct vnop_revoke_args /* {
+static int
+union_revoke(struct vnop_revoke_args *ap)
+/*
+       struct vnop_revoke_args {
                struct vnode *a_vp;
                int a_flags;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        struct vnode *vp = ap->a_vp;
 
@@ -819,16 +944,20 @@ union_revoke(ap)
        if (LOWERVP(vp))
                VNOP_REVOKE(LOWERVP(vp), ap->a_flags, ap->a_context);
        vnode_reclaim(vp);
+
+       return (0);
 }
 
-int
-union_mmap(ap)
-       struct vnop_mmap_args /* {
+static int
+union_mmap(struct vnop_mmap_args *ap)
+/*
+       struct vnop_mmap_args {
                struct vnode *a_vp;
                int  a_fflags;
                kauth_cred_t a_cred;
                struct proc *a_p;
-       } */ *ap;
+       } *ap;
+*/
 {
        register struct vnode *ovp = OTHERVP(ap->a_vp);
 
@@ -836,64 +965,102 @@ union_mmap(ap)
        return (VCALL(ovp, VOFFSET(vnop_mmap), ap));
 }
 
-int
-union_fsync(
-       struct vnop_fsync_args /* {
+static int
+union_mnomap(struct vnop_mnomap_args *ap)
+/*
+       struct vnop_mnomap_args {
+               struct vnode *a_vp;
+               int  a_fflags;
+               kauth_cred_t a_cred;
+               struct proc *a_p;
+       } *ap;
+*/
+{
+       register struct vnode *ovp = OTHERVP(ap->a_vp);
+
+       ap->a_vp = ovp;
+       return (VCALL(ovp, VOFFSET(vnop_mnomap), ap));
+}
+
+static int
+union_fsync(struct vnop_fsync_args *ap)
+/*
+       struct vnop_fsync_args {
                struct vnode *a_vp;
                int  a_waitfor;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        int error = 0;
-       struct proc *p = vfs_context_proc(ap->a_context);
        struct vnode *targetvp = OTHERVP(ap->a_vp);
 
        if (targetvp != NULLVP) {
-               int dolock = (targetvp == LOWERVP(ap->a_vp));
 
-               if (!dolock)
-                       FIXUP(VTOUNION(ap->a_vp), p);
                error = VNOP_FSYNC(targetvp, ap->a_waitfor, ap->a_context);
        }
 
        return (error);
 }
 
-int
-union_remove(
-       struct vnop_remove_args /* {
+static int
+union_remove(struct vnop_remove_args *ap)
+/*
+       struct vnop_remove_args {
                struct vnode *a_dvp;
                struct vnode *a_vp;
                struct componentname *a_cnp;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
-       int error;
+       int error, flags;
        struct union_node *dun = VTOUNION(ap->a_dvp);
        struct union_node *un = VTOUNION(ap->a_vp);
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
+       int busydel = 0;
 
        if (dun->un_uppervp == NULLVP)
                panic("union remove: null upper vnode");
 
+       if (UNNODE_FAULTIN(dun) && ((ap->a_vp != NULLVP) &&
+               ((vnode_isreg(ap->a_vp) != 0) || (vnode_islnk(ap->a_vp) != 0)))) {
+                       return(VNOP_REMOVE(dun->un_uppervp, ap->a_vp, ap->a_cnp, ap->a_flags, ap->a_context));
+       }
+
        if (un->un_uppervp != NULLVP) {
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
 
-               FIXUP(dun, p);
-               dun->un_flags |= UN_KLOCK;
-               FIXUP(un, p);
-               un->un_flags |= UN_KLOCK;
-
+               flags = ap->a_flags;
+               if (vnode_isinuse(ap->a_vp, 0))
+                       busydel = 1;
+               if ((flags & VNODE_REMOVE_NODELETEBUSY) && (busydel != 0)) {
+                               return(EBUSY);
+               }
                if (union_dowhiteout(un, cnp->cn_context))
                        cnp->cn_flags |= DOWHITEOUT;
+       
+               if (busydel != 0)  {
+                       union_lock();
+                       un->un_flags |= UN_DELETED;
+                       if (un->un_flags & UN_CACHED) {
+                               un->un_flags &= ~UN_CACHED;
+                               LIST_REMOVE(un, un_cache);
+                       }
+                       union_unlock();
+                       vnode_ref(vp);
+               }
                error = VNOP_REMOVE(dvp, vp, cnp, 0, ap->a_context);
-               if (!error)
-                       union_removed_upper(un);
+               if (!error) {
+                       union_lock();
+                       if (busydel == 0)
+                               union_removed_upper(un);
+                       union_unlock();
+               }
        } else {
-               FIXUP(dun, p);
+               if (UNNODE_FAULTIN(un))
+                       panic("faultfs: No uppervp");
                error = union_mkwhiteout(
                        MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
                        dun->un_uppervp, ap->a_cnp, un->un_path);
@@ -902,19 +1069,19 @@ union_remove(
        return (error);
 }
 
-int
-union_link(
-       struct vnop_link_args /* {
+static int
+union_link(struct vnop_link_args *ap)
+/*
+       struct vnop_link_args {
                struct vnode *a_vp;
                struct vnode *a_tdvp;
                struct componentname *a_cnp;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        int error = 0;
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
        struct union_node *un;
        struct vnode *vp;
        struct vnode *tdvp;
@@ -926,13 +1093,20 @@ union_link(
        } else {
                struct union_node *tun = VTOUNION(ap->a_vp);
                if (tun->un_uppervp == NULLVP) {
+                       if (UNNODE_FAULTIN(tun))
+                               panic("faultfs: No uppervp");
                        if (un->un_uppervp == tun->un_dirvp) {
-                               un->un_flags &= ~UN_ULOCK;
                        }
-                       error = union_copyup(tun, 1, vfs_context_ucred(ctx), p);
-                       if (un->un_uppervp == tun->un_dirvp) {
-                               un->un_flags |= UN_ULOCK;
+                       union_lock();
+                       /* Would need to drain for above,below mount and faulin does not enter this path */
+                       un->un_flags |= UN_LOCKED;
+                       error = union_copyup(tun, 1, ap->a_context);
+                       un->un_flags &= ~UN_LOCKED;
+                       if ((un->un_flags & UN_WANT) == UN_WANT) {
+                               un->un_flags &=  ~UN_WANT;
+                               wakeup(&un->un_flags);
                        }
+                       union_unlock();
                }
                vp = tun->un_uppervp;
        }
@@ -944,16 +1118,15 @@ union_link(
                return (error);
        }
 
-       FIXUP(un, p);
-       vnode_get(tdvp);
-       un->un_flags |= UN_KLOCK;
 
-       return (VNOP_LINK(vp, tdvp, cnp, ap->a_context));
+       error =  (VNOP_LINK(vp, tdvp, cnp, ap->a_context));
+       return(error);
 }
 
-int
-union_rename(ap)
-       struct vnop_rename_args  /* {
+static int
+union_rename(struct vnop_rename_args *ap)
+/*
+       struct vnop_rename_args {
                struct vnode *a_fdvp;
                struct vnode *a_fvp;
                struct componentname *a_fcnp;
@@ -961,7 +1134,8 @@ union_rename(ap)
                struct vnode *a_tvp;
                struct componentname *a_tcnp;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
 
@@ -970,9 +1144,12 @@ union_rename(ap)
        struct vnode *tdvp = ap->a_tdvp;
        struct vnode *tvp = ap->a_tvp;
 
+
        if (fdvp->v_op == union_vnodeop_p) {    /* always true */
                struct union_node *un = VTOUNION(fdvp);
                if (un->un_uppervp == NULLVP) {
+                       if (UNNODE_FAULTIN(un))
+                               panic("faultfs rename: No uppervp");
                        /*
                         * this should never happen in normal
                         * operation but might if there was
@@ -984,12 +1161,13 @@ union_rename(ap)
                }
 
                fdvp = un->un_uppervp;
-               vnode_get(fdvp);
        }
 
        if (fvp->v_op == union_vnodeop_p) {     /* always true */
                struct union_node *un = VTOUNION(fvp);
                if (un->un_uppervp == NULLVP) {
+                       if (UNNODE_FAULTIN(un))
+                               panic("faultfs rename: No uppervp");
                        /* XXX: should do a copyup */
                        error = EXDEV;
                        goto bad;
@@ -999,7 +1177,6 @@ union_rename(ap)
                        ap->a_fcnp->cn_flags |= DOWHITEOUT;
 
                fvp = un->un_uppervp;
-               vnode_get(fvp);
        }
 
        if (tdvp->v_op == union_vnodeop_p) {
@@ -1011,23 +1188,19 @@ union_rename(ap)
                         * a problem creating the top-level shadow
                         * directory.
                         */
+                       if (UNNODE_FAULTIN(un))
+                               panic("faultfs rename: No uppervp");
                        error = EXDEV;
                        goto bad;
                }
 
                tdvp = un->un_uppervp;
-               vnode_get(tdvp);
-               un->un_flags |= UN_KLOCK;
        }
 
        if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
                struct union_node *un = VTOUNION(tvp);
 
                tvp = un->un_uppervp;
-               if (tvp != NULLVP) {
-                       vnode_get(tvp);
-                       un->un_flags |= UN_KLOCK;
-               }
        }
 
        return (VNOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp, ap->a_context));
@@ -1036,36 +1209,36 @@ bad:
        return (error);
 }
 
-int
-union_mkdir(
-       struct vnop_mkdir_args /* {
+static int
+union_mkdir(struct vnop_mkdir_args *ap)
+/*
+       struct vnop_mkdir_args {
                struct vnode *a_dvp;
                struct vnode **a_vpp;
                struct componentname *a_cnp;
                struct vnode_attr *a_vap;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_dvp);
        struct vnode *dvp = un->un_uppervp;
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
 
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
 
-               FIXUP(un, p);
-               un->un_flags |= UN_KLOCK;
 
                /* note that this is a direct fallthrough to the filesystem */
                error = VNOP_MKDIR(dvp, &vp, cnp, ap->a_vap, ap->a_context);
                if (error)
                        return (error);
 
+               union_lock();
                error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp,
                                NULLVP, cnp, vp, NULLVP, 1);
+               union_unlock();
                if (error)
                        vnode_put(vp);
                return (error);
@@ -1073,22 +1246,24 @@ union_mkdir(
        return (EROFS);
 }
 
-int
-union_rmdir(
-       struct vnop_rmdir_args /* {
+static int
+union_rmdir(struct vnop_rmdir_args *ap)
+/*
+       struct vnop_rmdir_args {
                struct vnode *a_dvp;
                struct vnode *a_vp;
                struct componentname *a_cnp;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        int error;
        struct union_node *dun = VTOUNION(ap->a_dvp);
        struct union_node *un = VTOUNION(ap->a_vp);
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
+       int busydel = 0;
 
+       /******* NODE HAS TO BE LOCKED ******/
        if (dun->un_uppervp == NULLVP)
                panic("union rmdir: null upper vnode");
 
@@ -1096,20 +1271,31 @@ union_rmdir(
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
 
-               FIXUP(dun, p);
-               vnode_get(dvp);
-               dun->un_flags |= UN_KLOCK;
-               FIXUP(un, p);
-               vnode_get(vp);
-               un->un_flags |= UN_KLOCK;
+               if (vnode_isinuse(ap->a_vp, 0)) {
+                       busydel = 1;
+                       union_lock();
+                       un->un_flags |= UN_DELETED;
+                       if (un->un_flags & UN_CACHED) {
+                               un->un_flags &= ~UN_CACHED;
+                               LIST_REMOVE(un, un_cache);
+                       }
+                       union_unlock();
+                       vnode_ref(vp);
+               }
+
 
                if (union_dowhiteout(un, cnp->cn_context))
                        cnp->cn_flags |= DOWHITEOUT;
                error = VNOP_RMDIR(dvp, vp, ap->a_cnp, ap->a_context);
-               if (!error)
-                       union_removed_upper(un);
+               if (!error) {
+                       union_lock();
+                       if (busydel == 0)
+                               union_removed_upper(un);
+                       union_unlock();
+               }
        } else {
-               FIXUP(dun, p);
+               if (UNNODE_FAULTIN(un))
+                       panic("faultfs: No uppervp");
                error = union_mkwhiteout(
                        MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
                        dun->un_uppervp, ap->a_cnp, un->un_path);
@@ -1117,32 +1303,29 @@ union_rmdir(
        return (error);
 }
 
-int
-union_symlink(
-       struct vnop_symlink_args /* {
+static int
+union_symlink(struct vnop_symlink_args *ap)
+/*
+       struct vnop_symlink_args {
                struct vnode *a_dvp;
                struct vnode **a_vpp;
                struct componentname *a_cnp;
                struct vnode_attr *a_vap;
                char *a_target;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_dvp);
        struct vnode *dvp = un->un_uppervp;
        struct componentname *cnp = ap->a_cnp;
-       vfs_context_t ctx = cnp->cn_context;
-       struct proc *p = vfs_context_proc(ctx);
 
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
 
-               FIXUP(un, p);
-               un->un_flags |= UN_KLOCK;
-
                error = VNOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target, ap->a_context);
-               *ap->a_vpp = NULLVP;
+               *ap->a_vpp = vp;
                return (error);
        }
        return (EROFS);
@@ -1155,9 +1338,10 @@ union_symlink(
  * down the union stack.  readdir(3) is responsible for
  * eliminating duplicate names from the returned data stream.
  */
-int
-union_readdir(ap)
-       struct vnop_readdir_args /* {
+static int
+union_readdir(struct vnop_readdir_args *ap)
+/*
+       struct vnop_readdir_args {
                struct vnodeop_desc *a_desc;
                struct vnode *a_vp;
                struct uio *a_uio;
@@ -1165,11 +1349,11 @@ union_readdir(ap)
                int *a_eofflag;
                int *a_numdirent;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        struct union_node *un = VTOUNION(ap->a_vp);
        struct vnode *uvp = un->un_uppervp;
-       struct proc *p = vfs_context_proc(ap->a_context);
 
        if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
                return (EINVAL);
@@ -1177,43 +1361,40 @@ union_readdir(ap)
        if (uvp == NULLVP)
                return (0);
 
-       FIXUP(un, p);
        ap->a_vp = uvp;
        return (VCALL(uvp, VOFFSET(vnop_readdir), ap));
 }
 
-int
-union_readlink(ap)
-       struct vnop_readlink_args /* {
+static int
+union_readlink(struct vnop_readlink_args *ap)
+/*
+       struct vnop_readlink_args {
                struct vnode *a_vp;
                struct uio *a_uio;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
-       struct uio *uio = ap->a_uio;
-       struct proc *p = vfs_context_proc(ap->a_context);
        struct vnode *vp = OTHERVP(ap->a_vp);
-       int dolock = (vp == LOWERVP(ap->a_vp));
 
-       if (!dolock)
-               FIXUP(VTOUNION(ap->a_vp), p);
        ap->a_vp = vp;
        error = VCALL(vp, VOFFSET(vnop_readlink), ap);
 
        return (error);
 }
 
-int
-union_inactive(
-       struct vnop_inactive_args /* {
+static int
+union_inactive(struct vnop_inactive_args *ap)
+/*
+       struct vnop_inactive_args {
                struct vnode *a_vp;
                vfs_context_t a_context;
-       } */ *ap)
+       } *ap;
+*/
 {
        struct vnode *vp = ap->a_vp;
        struct union_node *un = VTOUNION(vp);
-       struct vnode **vpp;
 
        /*
         * Do nothing (and _don't_ bypass).
@@ -1228,35 +1409,47 @@ union_inactive(
         * That's too much work for now.
         */
 
-       if (un->un_dircache != 0) {
-               for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
-                       vnode_put(*vpp);
-               _FREE(un->un_dircache, M_TEMP);
-               un->un_dircache = 0;
+       union_lock();
+       if (un->un_flags & UN_DELETED) {
+               if(un->un_uppervp != NULLVP) {
+                       vnode_rele(un->un_uppervp);
+               }
+               union_removed_upper(un);
        }
 
-       if ((un->un_flags & UN_CACHED) == 0)
+       if (un->un_dircache != 0)  {
+                       union_dircache_free(un);
+       }
+       if (un->un_flags & UN_DIRENVN) {
                vnode_recycle(vp);
+       }
+
+       union_unlock();
 
        return (0);
 }
 
-int
-union_reclaim(ap)
-       struct vnop_reclaim_args /* {
+static int
+union_reclaim(struct vnop_reclaim_args *ap)
+/*
+       struct vnop_reclaim_args {
                struct vnode *a_vp;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
 
+       union_lock();
        union_freevp(ap->a_vp);
+       union_unlock();
 
        return (0);
 }
 
-int
-union_blockmap(ap)
-       struct vnop_blockmap_args /* {
+static int
+union_blockmap(struct vnop_blockmap_args *ap)
+/*
+       struct vnop_blockmap_args {
                struct vnode *a_vp;
                off_t a_offset;    
                size_t a_size;
@@ -1264,53 +1457,50 @@ union_blockmap(ap)
                size_t *a_run;
                void *a_poff;
                int a_flags;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
-       struct proc *p = current_proc();                /* XXX */
        struct vnode *vp = OTHERVP(ap->a_vp);
-       int dolock = (vp == LOWERVP(ap->a_vp));
 
-       if (!dolock)
-               FIXUP(VTOUNION(ap->a_vp), p);
        ap->a_vp = vp;
        error = VCALL(vp, VOFFSET(vnop_blockmap), ap);
 
        return (error);
 }
 
-int
-union_pathconf(ap)
-       struct vnop_pathconf_args /* {
+static int
+union_pathconf(struct vnop_pathconf_args *ap)
+/*
+       struct vnop_pathconf_args {
                struct vnode *a_vp;
                int a_name;
                int *a_retval;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
-       struct proc *p = current_proc();                /* XXX */
        struct vnode *vp = OTHERVP(ap->a_vp);
-       int dolock = (vp == LOWERVP(ap->a_vp));
 
-       if (!dolock)
-               FIXUP(VTOUNION(ap->a_vp), p);
        ap->a_vp = vp;
        error = VCALL(vp, VOFFSET(vnop_pathconf), ap);
 
        return (error);
 }
 
-int
-union_advlock(ap)
-       struct vnop_advlock_args /* {
+static int
+union_advlock(struct vnop_advlock_args *ap)
+/*
+       struct vnop_advlock_args {
                struct vnode *a_vp;
                caddr_t  a_id;
                int  a_op;
                struct flock *a_fl;
                int  a_flags;
                vfs_context_t a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        register struct vnode *ovp = OTHERVP(ap->a_vp);
 
@@ -1324,11 +1514,13 @@ union_advlock(ap)
  * vnode in its arguments.
  * This goes away with a merged VM/buffer cache.
  */
-int
-union_strategy(ap)
-       struct vnop_strategy_args /* {
+static int
+union_strategy(struct vnop_strategy_args *ap)
+/*
+       struct vnop_strategy_args {
                struct buf *a_bp;
-       } */ *ap;
+       } *ap;
+*/
 {
        struct buf *bp = ap->a_bp;
        int error;
@@ -1352,9 +1544,10 @@ union_strategy(ap)
 }
 
 /* Pagein */
-int
-union_pagein(ap)
-       struct vnop_pagein_args /* {
+static int
+union_pagein(struct vnop_pagein_args *ap)
+/*
+       struct vnop_pagein_args {
                struct vnode    *a_vp,
                upl_t           a_pl,
                vm_offset_t     a_pl_offset,
@@ -1362,7 +1555,8 @@ union_pagein(ap)
                size_t          a_size,
                int             a_flags
                vfs_context_t   a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
        struct vnode *vp = OTHERVP(ap->a_vp);
@@ -1381,11 +1575,17 @@ union_pagein(ap)
                off_t cur = ap->a_f_offset + (off_t)ap->a_pl_offset;
 
                if (vp == un->un_uppervp) {
-                       if (cur > un->un_uppersz)
+                       if (cur > un->un_uppersz) {
+                               union_lock();
                                union_newsize(ap->a_vp, cur, VNOVAL);
+                               union_unlock();
+                       }
                } else {
-                       if (cur > un->un_lowersz)
+                       if (cur > un->un_lowersz) {
+                               union_lock();
                                union_newsize(ap->a_vp, VNOVAL, cur);
+                               union_unlock();
+                       }
                }
        }
 
@@ -1393,9 +1593,10 @@ union_pagein(ap)
 }
 
 /* Pageout  */
-int
-union_pageout(ap)
-       struct vnop_pageout_args /* {
+static int
+union_pageout(struct vnop_pageout_args *ap)
+/*
+       struct vnop_pageout_args {
                struct vnode    *a_vp,
                upl_t           a_pl,
                vm_offset_t     a_pl_offset,
@@ -1403,7 +1604,8 @@ union_pageout(ap)
                size_t          a_size,
                int             a_flags
                vfs_context_t   a_context;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
        struct vnode *vp;
@@ -1423,21 +1625,26 @@ union_pageout(ap)
        if (error == 0) {
                off_t cur = ap->a_f_offset + (off_t)ap->a_pl_offset;
 
-               if (cur > un->un_uppersz)
+               if (cur > un->un_uppersz) {
+                       union_lock();
                        union_newsize(ap->a_vp, cur, VNOVAL);
+                       union_unlock();
+               }
        }
 
        return (error);
 }
 
 /* Blktooff derives file offset for the given logical block number */
-int
-union_blktooff(ap)
-       struct vnop_blktooff_args /* {
+static int
+union_blktooff(struct vnop_blktooff_args *ap)
+/*
+       struct vnop_blktooff_args {
                struct vnode *a_vp;
                daddr64_t a_lblkno;
                off_t *a_offset;    
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
        struct vnode *vp = OTHERVP(ap->a_vp);
@@ -1448,13 +1655,15 @@ union_blktooff(ap)
 }
 
 /* offtoblk derives file offset for the given logical block number */
-int
-union_offtoblk(ap)
-       struct vnop_offtoblk_args /* {
+static int
+union_offtoblk(struct vnop_offtoblk_args *ap)
+/*
+       struct vnop_offtoblk_args  {
                struct vnode *a_vp;
                off_t a_offset;    
                daddr64_t *a_lblkno;
-       } */ *ap;
+       } *ap;
+*/
 {
        int error;
        struct vnode *vp = OTHERVP(ap->a_vp);
@@ -1487,6 +1696,7 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = {
        { &vnop_select_desc, (VOPFUNC)union_select },           /* select */
        { &vnop_revoke_desc, (VOPFUNC)union_revoke },           /* revoke */
        { &vnop_mmap_desc, (VOPFUNC)union_mmap },               /* mmap */
+       { &vnop_mnomap_desc, (VOPFUNC)union_mnomap },           /* mnomap */
        { &vnop_fsync_desc, (VOPFUNC)union_fsync },             /* fsync */
        { &vnop_remove_desc, (VOPFUNC)union_remove },           /* remove */
        { &vnop_link_desc, (VOPFUNC)union_link },               /* link */