X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0c530ab8987f0ae6a1a3d9284f40182b88852816..2d21ac55c334faf3a56e5634905ed6987fc787d4:/bsd/miscfs/union/union_vnops.c

diff --git a/bsd/miscfs/union/union_vnops.c b/bsd/miscfs/union/union_vnops.c
index 4b1ca8ef1..240ab9f40 100644
--- a/bsd/miscfs/union/union_vnops.c
+++ b/bsd/miscfs/union/union_vnops.c
@@ -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 */
 /*
@@ -77,23 +83,10 @@
 #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 */