xref: /netbsd/sys/fs/unionfs/unionfs_subr.c (revision bfecfc14)
11a710239Sad /*-
21a710239Sad  * Copyright (c) 1994 Jan-Simon Pendry
31a710239Sad  * Copyright (c) 1994
41a710239Sad  *	The Regents of the University of California.  All rights reserved.
51a710239Sad  * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
61a710239Sad  * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org>
71a710239Sad  *
81a710239Sad  * This code is derived from software contributed to Berkeley by
91a710239Sad  * Jan-Simon Pendry.
101a710239Sad  *
111a710239Sad  * Redistribution and use in source and binary forms, with or without
121a710239Sad  * modification, are permitted provided that the following conditions
131a710239Sad  * are met:
141a710239Sad  * 1. Redistributions of source code must retain the above copyright
151a710239Sad  *    notice, this list of conditions and the following disclaimer.
161a710239Sad  * 2. Redistributions in binary form must reproduce the above copyright
171a710239Sad  *    notice, this list of conditions and the following disclaimer in the
181a710239Sad  *    documentation and/or other materials provided with the distribution.
191a710239Sad  * 4. Neither the name of the University nor the names of its contributors
201a710239Sad  *    may be used to endorse or promote products derived from this software
211a710239Sad  *    without specific prior written permission.
221a710239Sad  *
231a710239Sad  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
241a710239Sad  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
251a710239Sad  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
261a710239Sad  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
271a710239Sad  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
281a710239Sad  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
291a710239Sad  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
301a710239Sad  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
311a710239Sad  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
321a710239Sad  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
331a710239Sad  * SUCH DAMAGE.
341a710239Sad  *
351a710239Sad  *	@(#)union_subr.c	8.20 (Berkeley) 5/20/95
361a710239Sad  * $FreeBSD: src/sys/fs/unionfs/union_subr.c,v 1.99 2008/01/24 12:34:27 attilio Exp $
371a710239Sad  */
381a710239Sad 
391a710239Sad #include <sys/param.h>
401a710239Sad #include <sys/systm.h>
411a710239Sad #include <sys/kernel.h>
421a710239Sad #include <sys/lock.h>
431a710239Sad #include <sys/mutex.h>
441a710239Sad #include <sys/malloc.h>
451a710239Sad #include <sys/mount.h>
461a710239Sad #include <sys/namei.h>
471a710239Sad #include <sys/proc.h>
481a710239Sad #include <sys/vnode.h>
491a710239Sad #include <sys/dirent.h>
501a710239Sad #include <sys/fcntl.h>
511a710239Sad #include <sys/filedesc.h>
521a710239Sad #include <sys/stat.h>
531a710239Sad #include <sys/kauth.h>
541a710239Sad #include <sys/resourcevar.h>
551a710239Sad 
561a710239Sad #include <fs/unionfs/unionfs.h>
571a710239Sad 
581a710239Sad MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
591a710239Sad 
601a710239Sad /*
611a710239Sad  * Make a new or get existing unionfs node.
621a710239Sad  *
631a710239Sad  * uppervp and lowervp should be unlocked. Because if new unionfs vnode is
641a710239Sad  * locked, uppervp or lowervp is locked too. In order to prevent dead lock,
651a710239Sad  * you should not lock plurality simultaneously.
661a710239Sad  */
671a710239Sad int
unionfs_nodeget(struct mount * mp,struct vnode * uppervp,struct vnode * lowervp,struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp)681a710239Sad unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
691a710239Sad 		struct vnode *lowervp, struct vnode *dvp,
701a710239Sad 		struct vnode **vpp, struct componentname *cnp)
711a710239Sad {
721a710239Sad 	struct unionfs_mount *ump;
731a710239Sad 	struct unionfs_node *unp;
741a710239Sad 	struct vnode   *vp;
751a710239Sad 	int		error;
761a710239Sad 	const char	*path;
771a710239Sad 
781a710239Sad 	ump = MOUNTTOUNIONFSMOUNT(mp);
791a710239Sad 	path = (cnp ? cnp->cn_nameptr : NULL);
801a710239Sad 
811a710239Sad 	if (uppervp == NULLVP && lowervp == NULLVP)
821a710239Sad 		panic("unionfs_nodeget: upper and lower is null");
831a710239Sad 
841a710239Sad 	/* If it has no ISLASTCN flag, path check is skipped. */
851a710239Sad 	if (cnp && !(cnp->cn_flags & ISLASTCN))
861a710239Sad 		path = NULL;
871a710239Sad 
881a710239Sad 	if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
891a710239Sad 	    (lowervp == NULLVP || ump->um_lowervp != lowervp)) {
901a710239Sad 		if (dvp == NULLVP)
911a710239Sad 			return (EINVAL);
921a710239Sad 	}
931a710239Sad 
94f1146e73Srmind 	/*
95f1146e73Srmind 	 * Get a new vnode and share the lock with upper layer vnode,
96f1146e73Srmind 	 * unless layers are inverted.
97f1146e73Srmind 	 */
98f1146e73Srmind 	vnode_t *svp = (uppervp != NULLVP) ? uppervp : lowervp;
99*bfecfc14Schristos 	error = vcache_get(mp, svp, sizeof(svp), &vp);
1001a710239Sad 	if (error != 0) {
1011a710239Sad 		return (error);
1021a710239Sad 	}
1031a710239Sad 	if (dvp != NULLVP)
1041a710239Sad 		vref(dvp);
1051a710239Sad 	if (uppervp != NULLVP)
1061a710239Sad 		vref(uppervp);
1071a710239Sad 	if (lowervp != NULLVP)
1081a710239Sad 		vref(lowervp);
1091a710239Sad 
110f1146e73Srmind 	unp = kmem_zalloc(sizeof(*unp), KM_SLEEP);
1111a710239Sad 	unp->un_vnode = vp;
1121a710239Sad 	unp->un_uppervp = uppervp;
1131a710239Sad 	unp->un_lowervp = lowervp;
1141a710239Sad 	unp->un_dvp = dvp;
1151a710239Sad 
1161a710239Sad 	if (path != NULL) {
1171a710239Sad 		unp->un_path = (char *)
1181a710239Sad 		    malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
119e2cb8590Scegger 		memcpy(unp->un_path, cnp->cn_nameptr, cnp->cn_namelen);
1201a710239Sad 		unp->un_path[cnp->cn_namelen] = '\0';
1211a710239Sad 	}
1221a710239Sad 	vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
1231a710239Sad 	vp->v_data = unp;
1241a710239Sad 	uvm_vnp_setsize(vp, 0);
1251a710239Sad 
1261a710239Sad 	if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
1271a710239Sad 	    (lowervp != NULLVP && ump->um_lowervp == lowervp))
1281a710239Sad 		vp->v_vflag |= VV_ROOT;
1291a710239Sad 
1301a710239Sad 	*vpp = vp;
1311a710239Sad 
1321a710239Sad 	return (0);
1331a710239Sad }
1341a710239Sad 
1351a710239Sad /*
1361a710239Sad  * Clean up the unionfs node.
1371a710239Sad  */
1381a710239Sad void
unionfs_noderem(struct vnode * vp)1391a710239Sad unionfs_noderem(struct vnode *vp)
1401a710239Sad {
1411a710239Sad 	struct unionfs_node *unp;
1421a710239Sad 	struct unionfs_node_status *unsp;
1431a710239Sad 	struct vnode   *lvp;
1441a710239Sad 	struct vnode   *uvp;
1451a710239Sad 
1461a710239Sad 	/*
1471a710239Sad 	 * Use the interlock to protect the clearing of v_data to
1481a710239Sad 	 * prevent faults in unionfs_lock().
1491a710239Sad 	 */
1501a710239Sad 	unp = VTOUNIONFS(vp);
1511a710239Sad 	lvp = unp->un_lowervp;
1521a710239Sad 	uvp = unp->un_uppervp;
1531a710239Sad 	unp->un_lowervp = unp->un_uppervp = NULLVP;
1541a710239Sad 	vp->v_data = NULL;
1551a710239Sad 
1561a710239Sad 	if (lvp != NULLVP)
1571a710239Sad 		vrele(lvp);
1581a710239Sad 	if (uvp != NULLVP)
1591a710239Sad 		vrele(uvp);
1601a710239Sad 	if (unp->un_dvp != NULLVP) {
1611a710239Sad 		vrele(unp->un_dvp);
1621a710239Sad 		unp->un_dvp = NULLVP;
1631a710239Sad 	}
1641a710239Sad 	if (unp->un_path) {
1651a710239Sad 		free(unp->un_path, M_UNIONFSPATH);
1661a710239Sad 		unp->un_path = NULL;
1671a710239Sad 	}
1681a710239Sad 
1691a710239Sad 	while ((unsp = LIST_FIRST(&(unp->un_unshead))) != NULL) {
1701a710239Sad 		LIST_REMOVE(unsp, uns_list);
1711a710239Sad 		free(unsp, M_TEMP);
1721a710239Sad 	}
1731a710239Sad 	kmem_free(unp, sizeof(*unp));
1741a710239Sad }
1751a710239Sad 
1761a710239Sad /*
1771a710239Sad  * Get the unionfs node status.
1781a710239Sad  * You need exclusive lock this vnode.
1791a710239Sad  */
1801a710239Sad void
unionfs_get_node_status(struct unionfs_node * unp,struct unionfs_node_status ** unspp)1811a710239Sad unionfs_get_node_status(struct unionfs_node *unp,
1821a710239Sad 			struct unionfs_node_status **unspp)
1831a710239Sad {
1841a710239Sad 	struct unionfs_node_status *unsp;
1851a710239Sad 	pid_t pid;
1861a710239Sad 	lwpid_t lid;
1871a710239Sad 
1881a710239Sad 	KASSERT(NULL != unspp);
1891a710239Sad 	KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE);
1901a710239Sad 
1911a710239Sad 	pid = curproc->p_pid;
1921a710239Sad 	lid = curlwp->l_lid;
1931a710239Sad 
1941a710239Sad 	LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
1951a710239Sad 		if (unsp->uns_pid == pid && unsp->uns_lid == lid) {
1961a710239Sad 			*unspp = unsp;
1971a710239Sad 			return;
1981a710239Sad 		}
1991a710239Sad 	}
2001a710239Sad 
2011a710239Sad 	/* create a new unionfs node status */
2021a710239Sad 	unsp = kmem_zalloc(sizeof(*unsp), KM_SLEEP);
2031a710239Sad 	unsp->uns_pid = pid;
2041a710239Sad 	unsp->uns_lid = lid;
2051a710239Sad 	LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
2061a710239Sad 
2071a710239Sad 	*unspp = unsp;
2081a710239Sad }
2091a710239Sad 
2101a710239Sad /*
2111a710239Sad  * Remove the unionfs node status, if you can.
2121a710239Sad  * You need exclusive lock this vnode.
2131a710239Sad  */
2141a710239Sad void
unionfs_tryrem_node_status(struct unionfs_node * unp,struct unionfs_node_status * unsp)2151a710239Sad unionfs_tryrem_node_status(struct unionfs_node *unp,
2161a710239Sad 			   struct unionfs_node_status *unsp)
2171a710239Sad {
2181a710239Sad 	KASSERT(NULL != unsp);
2191a710239Sad 	KASSERT(VOP_ISLOCKED(UNIONFSTOV(unp)) == LK_EXCLUSIVE);
2201a710239Sad 
2211a710239Sad 	if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
2221a710239Sad 		return;
2231a710239Sad 
2241a710239Sad 	LIST_REMOVE(unsp, uns_list);
2251a710239Sad 	kmem_free(unsp, sizeof(*unsp));
2261a710239Sad }
2271a710239Sad 
2281a710239Sad /*
2291a710239Sad  * Create upper node attr.
2301a710239Sad  */
2311a710239Sad void
unionfs_create_uppervattr_core(struct unionfs_mount * ump,struct vattr * lva,struct vattr * uva)2321a710239Sad unionfs_create_uppervattr_core(struct unionfs_mount *ump,
2331a710239Sad 			       struct vattr *lva,
2341a710239Sad 			       struct vattr *uva)
2351a710239Sad {
236c3183f32Spooka 	vattr_null(uva);
2371a710239Sad 	uva->va_type = lva->va_type;
2381a710239Sad 	uva->va_atime = lva->va_atime;
2391a710239Sad 	uva->va_mtime = lva->va_mtime;
2401a710239Sad 	uva->va_ctime = lva->va_ctime;
2411a710239Sad 
2421a710239Sad 	switch (ump->um_copymode) {
2431a710239Sad 	case UNIONFS_TRANSPARENT:
2441a710239Sad 		uva->va_mode = lva->va_mode;
2451a710239Sad 		uva->va_uid = lva->va_uid;
2461a710239Sad 		uva->va_gid = lva->va_gid;
2471a710239Sad 		break;
2481a710239Sad 	case UNIONFS_MASQUERADE:
2491a710239Sad 		if (ump->um_uid == lva->va_uid) {
2501a710239Sad 			uva->va_mode = lva->va_mode & 077077;
2511a710239Sad 			uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
2521a710239Sad 			uva->va_uid = lva->va_uid;
2531a710239Sad 			uva->va_gid = lva->va_gid;
2541a710239Sad 		} else {
2551a710239Sad 			uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
2561a710239Sad 			uva->va_uid = ump->um_uid;
2571a710239Sad 			uva->va_gid = ump->um_gid;
2581a710239Sad 		}
2591a710239Sad 		break;
2601a710239Sad 	default:		/* UNIONFS_TRADITIONAL */
2611a710239Sad 		uva->va_mode = 0777 & ~curproc->p_cwdi->cwdi_cmask;
2621a710239Sad 		uva->va_uid = ump->um_uid;
2631a710239Sad 		uva->va_gid = ump->um_gid;
2641a710239Sad 		break;
2651a710239Sad 	}
2661a710239Sad }
2671a710239Sad 
2681a710239Sad /*
2691a710239Sad  * Create upper node attr.
2701a710239Sad  */
2711a710239Sad int
unionfs_create_uppervattr(struct unionfs_mount * ump,struct vnode * lvp,struct vattr * uva,kauth_cred_t cred)2721a710239Sad unionfs_create_uppervattr(struct unionfs_mount *ump,
2731a710239Sad 			  struct vnode *lvp,
2741a710239Sad 			  struct vattr *uva,
2751a710239Sad 			  kauth_cred_t cred)
2761a710239Sad {
2771a710239Sad 	int		error;
2781a710239Sad 	struct vattr	lva;
2791a710239Sad 
2801a710239Sad 	if ((error = VOP_GETATTR(lvp, &lva, cred)))
2811a710239Sad 		return (error);
2821a710239Sad 
2831a710239Sad 	unionfs_create_uppervattr_core(ump, &lva, uva);
2841a710239Sad 
2851a710239Sad 	return (error);
2861a710239Sad }
2871a710239Sad 
2881a710239Sad /*
2891a710239Sad  * relookup
2901a710239Sad  *
2911a710239Sad  * dvp should be locked on entry and will be locked on return.
2921a710239Sad  *
2931a710239Sad  * If an error is returned, *vpp will be invalid, otherwise it will hold a
2941a710239Sad  * locked, referenced vnode. If *vpp == dvp then remember that only one
2951a710239Sad  * LK_EXCLUSIVE lock is held.
2961a710239Sad  */
2971a710239Sad static int
unionfs_relookup(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,struct componentname * cn,char ** pnbuf_ret,const char * path,int pathlen,u_long nameiop)2981a710239Sad unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
2991a710239Sad 		 struct componentname *cnp, struct componentname *cn,
300d4eb0539Sdholland 		 char **pnbuf_ret,
3011a710239Sad 		 const char *path, int pathlen, u_long nameiop)
3021a710239Sad {
3031a710239Sad 	int	error;
304d4eb0539Sdholland 	char *pnbuf;
3051a710239Sad 
3061a710239Sad 	cn->cn_namelen = pathlen;
307d4eb0539Sdholland 	pnbuf = PNBUF_GET();
308d4eb0539Sdholland 	memcpy(pnbuf, path, pathlen);
309d4eb0539Sdholland 	pnbuf[pathlen] = '\0';
3101a710239Sad 
3111a710239Sad 	cn->cn_nameiop = nameiop;
31214402d0fSdholland 	cn->cn_flags = (LOCKPARENT | LOCKLEAF | ISLASTCN);
3131a710239Sad 	cn->cn_cred = cnp->cn_cred;
3141a710239Sad 
315d4eb0539Sdholland 	cn->cn_nameptr = pnbuf;
3161a710239Sad 
3171a710239Sad 	if (nameiop == DELETE)
318eb2c22d2Sdholland 		cn->cn_flags |= (cnp->cn_flags & DOWHITEOUT);
3191a710239Sad 
3201a710239Sad 	vref(dvp);
3211423e65bShannken 	VOP_UNLOCK(dvp);
3221a710239Sad 
323eb2c22d2Sdholland 	if ((error = relookup(dvp, vpp, cn, 0))) {
324d4eb0539Sdholland 		PNBUF_PUT(pnbuf);
325d4eb0539Sdholland 		*pnbuf_ret = NULL;
3261a710239Sad 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
327d4eb0539Sdholland 	} else {
328d4eb0539Sdholland 		*pnbuf_ret = pnbuf;
3291a710239Sad 		vrele(dvp);
330d4eb0539Sdholland 	}
3311a710239Sad 
3321a710239Sad 	return (error);
3331a710239Sad }
3341a710239Sad 
3351a710239Sad /*
3361a710239Sad  * relookup for CREATE namei operation.
3371a710239Sad  *
3381a710239Sad  * dvp is unionfs vnode. dvp should be locked.
3391a710239Sad  *
3401a710239Sad  * If it called 'unionfs_copyfile' function by unionfs_link etc,
3411a710239Sad  * VOP_LOOKUP information is broken.
3421a710239Sad  * So it need relookup in order to create link etc.
3431a710239Sad  */
3441a710239Sad int
unionfs_relookup_for_create(struct vnode * dvp,struct componentname * cnp)3451a710239Sad unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp)
3461a710239Sad {
3471a710239Sad 	int	error;
3481a710239Sad 	struct vnode *udvp;
3491a710239Sad 	struct vnode *vp;
3501a710239Sad 	struct componentname cn;
351d4eb0539Sdholland 	char *pnbuf;
3521a710239Sad 
3531a710239Sad 	udvp = UNIONFSVPTOUPPERVP(dvp);
3541a710239Sad 	vp = NULLVP;
3551a710239Sad 
356d4eb0539Sdholland 	error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf,
357d4eb0539Sdholland 	    cnp->cn_nameptr,
3581a710239Sad 	    strlen(cnp->cn_nameptr), CREATE);
3591a710239Sad 	if (error)
3601a710239Sad 		return (error);
3611a710239Sad 
3621a710239Sad 	if (vp != NULLVP) {
3631a710239Sad 		if (udvp == vp)
3641a710239Sad 			vrele(vp);
3651a710239Sad 		else
3661a710239Sad 			vput(vp);
3671a710239Sad 
3681a710239Sad 		error = EEXIST;
3691a710239Sad 	}
3701a710239Sad 
371d4eb0539Sdholland 	PNBUF_PUT(pnbuf);
3721a710239Sad 
3731a710239Sad 	if (!error) {
3741a710239Sad 		cnp->cn_flags = cn.cn_flags;
3751a710239Sad 	}
3761a710239Sad 
3771a710239Sad 	return (error);
3781a710239Sad }
3791a710239Sad 
3801a710239Sad /*
3811a710239Sad  * relookup for DELETE namei operation.
3821a710239Sad  *
3831a710239Sad  * dvp is unionfs vnode. dvp should be locked.
3841a710239Sad  */
3851a710239Sad int
unionfs_relookup_for_delete(struct vnode * dvp,struct componentname * cnp)3861a710239Sad unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp)
3871a710239Sad {
3881a710239Sad 	int	error;
3891a710239Sad 	struct vnode *udvp;
3901a710239Sad 	struct vnode *vp;
3911a710239Sad 	struct componentname cn;
392d4eb0539Sdholland 	char *pnbuf;
3931a710239Sad 
3941a710239Sad 	udvp = UNIONFSVPTOUPPERVP(dvp);
3951a710239Sad 	vp = NULLVP;
3961a710239Sad 
397d4eb0539Sdholland 	error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr,
3981a710239Sad 	    strlen(cnp->cn_nameptr), DELETE);
3991a710239Sad 	if (error)
4001a710239Sad 		return (error);
4011a710239Sad 
4021a710239Sad 	if (vp == NULLVP)
4031a710239Sad 		error = ENOENT;
4041a710239Sad 	else {
4051a710239Sad 		if (udvp == vp)
4061a710239Sad 			vrele(vp);
4071a710239Sad 		else
4081a710239Sad 			vput(vp);
4091a710239Sad 	}
4101a710239Sad 
411d4eb0539Sdholland 	PNBUF_PUT(pnbuf);
4121a710239Sad 
4131a710239Sad 	if (!error) {
4141a710239Sad 		cnp->cn_flags = cn.cn_flags;
4151a710239Sad 	}
4161a710239Sad 
4171a710239Sad 	return (error);
4181a710239Sad }
4191a710239Sad 
4201a710239Sad /*
4211a710239Sad  * relookup for RENAME namei operation.
4221a710239Sad  *
4231a710239Sad  * dvp is unionfs vnode. dvp should be locked.
4241a710239Sad  */
4251a710239Sad int
unionfs_relookup_for_rename(struct vnode * dvp,struct componentname * cnp)4261a710239Sad unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp)
4271a710239Sad {
4281a710239Sad 	int error;
4291a710239Sad 	struct vnode *udvp;
4301a710239Sad 	struct vnode *vp;
4311a710239Sad 	struct componentname cn;
432d4eb0539Sdholland 	char *pnbuf;
4331a710239Sad 
4341a710239Sad 	udvp = UNIONFSVPTOUPPERVP(dvp);
4351a710239Sad 	vp = NULLVP;
4361a710239Sad 
437d4eb0539Sdholland 	error = unionfs_relookup(udvp, &vp, cnp, &cn, &pnbuf, cnp->cn_nameptr,
4381a710239Sad 	    strlen(cnp->cn_nameptr), RENAME);
4391a710239Sad 	if (error)
4401a710239Sad 		return (error);
4411a710239Sad 
4421a710239Sad 	if (vp != NULLVP) {
4431a710239Sad 		if (udvp == vp)
4441a710239Sad 			vrele(vp);
4451a710239Sad 		else
4461a710239Sad 			vput(vp);
4471a710239Sad 	}
4481a710239Sad 
449d4eb0539Sdholland 	PNBUF_PUT(pnbuf);
4501a710239Sad 
4511a710239Sad 	if (!error) {
4521a710239Sad 		cnp->cn_flags = cn.cn_flags;
4531a710239Sad 	}
4541a710239Sad 
4551a710239Sad 	return (error);
4561a710239Sad 
4571a710239Sad }
4581a710239Sad 
4591a710239Sad /*
4601a710239Sad  * Update the unionfs_node.
4611a710239Sad  *
4621a710239Sad  * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
4631a710239Sad  * uvp's lock and lower's lock will be unlocked.
4641a710239Sad  */
4651a710239Sad static void
unionfs_node_update(struct unionfs_node * unp,struct vnode * uvp)4661a710239Sad unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp)
4671a710239Sad {
4681a710239Sad 	struct vnode   *vp;
4691a710239Sad 	struct vnode   *lvp;
4701a710239Sad 
4711a710239Sad 	vp = UNIONFSTOV(unp);
4721a710239Sad 	lvp = unp->un_lowervp;
4731a710239Sad 
4741a710239Sad 	/*
4751a710239Sad 	 * lock update
4761a710239Sad 	 */
477f1146e73Srmind 	mutex_enter(vp->v_interlock);
4781a710239Sad 	unp->un_uppervp = uvp;
479f6c438baShannken 	KASSERT(VOP_ISLOCKED(lvp) == LK_EXCLUSIVE);
480f1146e73Srmind 	mutex_exit(vp->v_interlock);
4811a710239Sad }
4821a710239Sad 
4831a710239Sad /*
4841a710239Sad  * Create a new shadow dir.
4851a710239Sad  *
4861a710239Sad  * udvp should be locked on entry and will be locked on return.
4871a710239Sad  *
4881a710239Sad  * If no error returned, unp will be updated.
4891a710239Sad  */
4901a710239Sad int
unionfs_mkshadowdir(struct unionfs_mount * ump,struct vnode * udvp,struct unionfs_node * unp,struct componentname * cnp)4911a710239Sad unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
4921a710239Sad 		    struct unionfs_node *unp, struct componentname *cnp)
4931a710239Sad {
4941a710239Sad 	int		error;
4951a710239Sad 	struct vnode   *lvp;
4961a710239Sad 	struct vnode   *uvp;
4971a710239Sad 	struct vattr	va;
4981a710239Sad 	struct vattr	lva;
4991a710239Sad 	struct componentname cn;
500d4eb0539Sdholland 	char *pnbuf;
5011a710239Sad 
5021a710239Sad 	if (unp->un_uppervp != NULLVP)
5031a710239Sad 		return (EEXIST);
5041a710239Sad 
5051a710239Sad 	lvp = unp->un_lowervp;
5061a710239Sad 	uvp = NULLVP;
5071a710239Sad 
5081a710239Sad 	memset(&cn, 0, sizeof(cn));
5091a710239Sad 
5101a710239Sad 	if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred)))
5111a710239Sad 		goto unionfs_mkshadowdir_abort;
5121a710239Sad 
513d4eb0539Sdholland 	if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, &pnbuf,
514d4eb0539Sdholland 			cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
5151a710239Sad 		goto unionfs_mkshadowdir_abort;
5161a710239Sad 	if (uvp != NULLVP) {
5171a710239Sad 		if (udvp == uvp)
5181a710239Sad 			vrele(uvp);
5191a710239Sad 		else
5201a710239Sad 			vput(uvp);
5211a710239Sad 
5221a710239Sad 		error = EEXIST;
5231a710239Sad 		goto unionfs_mkshadowdir_free_out;
5241a710239Sad 	}
5251a710239Sad 
5261a710239Sad 	unionfs_create_uppervattr_core(ump, &lva, &va);
5271a710239Sad 
5281a710239Sad 	error = VOP_MKDIR(udvp, &uvp, &cn, &va);
5291a710239Sad 
5301a710239Sad 	if (!error) {
5311a710239Sad 		unionfs_node_update(unp, uvp);
5321a710239Sad 
5331a710239Sad 		/*
5341a710239Sad 		 * XXX The bug which cannot set uid/gid was corrected.
5351a710239Sad 		 * Ignore errors.   XXXNETBSD Why is this done as root?
5361a710239Sad 		 */
5371a710239Sad 		va.va_type = VNON;
5381a710239Sad 		VOP_SETATTR(uvp, &va, lwp0.l_cred);
5391a710239Sad 	}
5401a710239Sad 
5411a710239Sad unionfs_mkshadowdir_free_out:
542d4eb0539Sdholland 	PNBUF_PUT(pnbuf);
5431a710239Sad 
5441a710239Sad unionfs_mkshadowdir_abort:
5451a710239Sad 
5461a710239Sad 	return (error);
5471a710239Sad }
5481a710239Sad 
5491a710239Sad /*
5501a710239Sad  * Create a new whiteout.
5511a710239Sad  *
5521a710239Sad  * dvp should be locked on entry and will be locked on return.
5531a710239Sad  */
5541a710239Sad int
unionfs_mkwhiteout(struct vnode * dvp,struct componentname * cnp,const char * path)5551a710239Sad unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, const char *path)
5561a710239Sad {
5571a710239Sad 	int		error;
5581a710239Sad 	struct vnode   *wvp;
5591a710239Sad 	struct componentname cn;
560d4eb0539Sdholland 	char *pnbuf;
5611a710239Sad 
5621a710239Sad 	if (path == NULL)
5631a710239Sad 		path = cnp->cn_nameptr;
5641a710239Sad 
5651a710239Sad 	wvp = NULLVP;
566d4eb0539Sdholland 	if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, &pnbuf,
567d4eb0539Sdholland 			path, strlen(path), CREATE)))
5681a710239Sad 		return (error);
5691a710239Sad 	if (wvp != NULLVP) {
570d4eb0539Sdholland 		PNBUF_PUT(pnbuf);
5711a710239Sad 		if (dvp == wvp)
5721a710239Sad 			vrele(wvp);
5731a710239Sad 		else
5741a710239Sad 			vput(wvp);
5751a710239Sad 
5761a710239Sad 		return (EEXIST);
5771a710239Sad 	}
5781a710239Sad 
579d4eb0539Sdholland 	PNBUF_PUT(pnbuf);
5801a710239Sad 
5811a710239Sad 	return (error);
5821a710239Sad }
5831a710239Sad 
5841a710239Sad /*
5851a710239Sad  * Create a new vnode for create a new shadow file.
5861a710239Sad  *
5871a710239Sad  * If an error is returned, *vpp will be invalid, otherwise it will hold a
5881a710239Sad  * locked, referenced and opened vnode.
5891a710239Sad  *
5901a710239Sad  * unp is never updated.
5911a710239Sad  */
5921a710239Sad static int
unionfs_vn_create_on_upper(struct vnode ** vpp,struct vnode * udvp,struct unionfs_node * unp,struct vattr * uvap)5931a710239Sad unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
5941a710239Sad 			   struct unionfs_node *unp, struct vattr *uvap)
5951a710239Sad {
5961a710239Sad 	struct unionfs_mount *ump;
5971a710239Sad 	struct vnode   *vp;
5981a710239Sad 	struct vnode   *lvp;
5991a710239Sad 	kauth_cred_t    cred;
6001a710239Sad 	struct vattr	lva;
6011a710239Sad 	int		fmode;
6021a710239Sad 	int		error;
6031a710239Sad 	struct componentname cn;
604d4eb0539Sdholland 	char *pnbuf;
6051a710239Sad 
6061a710239Sad 	ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
6071a710239Sad 	vp = NULLVP;
6081a710239Sad 	lvp = unp->un_lowervp;
6091a710239Sad 	cred = kauth_cred_get();
6101a710239Sad 	fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
6111a710239Sad 	error = 0;
6121a710239Sad 
6131a710239Sad 	if ((error = VOP_GETATTR(lvp, &lva, cred)) != 0)
6141a710239Sad 		return (error);
6151a710239Sad 	unionfs_create_uppervattr_core(ump, &lva, uvap);
6161a710239Sad 
6171a710239Sad 	if (unp->un_path == NULL)
6181a710239Sad 		panic("unionfs: un_path is null");
6191a710239Sad 
6201a710239Sad 	cn.cn_namelen = strlen(unp->un_path);
621d4eb0539Sdholland 	pnbuf = PNBUF_GET();
622d4eb0539Sdholland 	memcpy(pnbuf, unp->un_path, cn.cn_namelen + 1);
6231a710239Sad 	cn.cn_nameiop = CREATE;
62414402d0fSdholland 	cn.cn_flags = (LOCKPARENT | LOCKLEAF | ISLASTCN);
6251a710239Sad 	cn.cn_cred = cred;
626d4eb0539Sdholland 	cn.cn_nameptr = pnbuf;
6271a710239Sad 
6281a710239Sad 	vref(udvp);
629eb2c22d2Sdholland 	if ((error = relookup(udvp, &vp, &cn, 0)) != 0)
6301a710239Sad 		goto unionfs_vn_create_on_upper_free_out2;
6311a710239Sad 	vrele(udvp);
6321a710239Sad 
6331a710239Sad 	if (vp != NULLVP) {
6341a710239Sad 		if (vp == udvp)
6351a710239Sad 			vrele(vp);
6361a710239Sad 		else
6371a710239Sad 			vput(vp);
6381a710239Sad 		error = EEXIST;
6391a710239Sad 		goto unionfs_vn_create_on_upper_free_out1;
6401a710239Sad 	}
6411a710239Sad 
6421a710239Sad 	if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0)
6431a710239Sad 		goto unionfs_vn_create_on_upper_free_out1;
6441a710239Sad 
6451a710239Sad 	if ((error = VOP_OPEN(vp, fmode, cred)) != 0) {
6461a710239Sad 		vput(vp);
6471a710239Sad 		goto unionfs_vn_create_on_upper_free_out1;
6481a710239Sad 	}
6491a710239Sad 	vp->v_writecount++;
6501a710239Sad 	*vpp = vp;
6511a710239Sad 
6521a710239Sad unionfs_vn_create_on_upper_free_out1:
6531423e65bShannken 	VOP_UNLOCK(udvp);
6541a710239Sad 
6551a710239Sad unionfs_vn_create_on_upper_free_out2:
656d4eb0539Sdholland 	PNBUF_PUT(pnbuf);
6571a710239Sad 
6581a710239Sad 	return (error);
6591a710239Sad }
6601a710239Sad 
6611a710239Sad /*
6621a710239Sad  * Copy from lvp to uvp.
6631a710239Sad  *
6641a710239Sad  * lvp and uvp should be locked and opened on entry and will be locked and
6651a710239Sad  * opened on return.
6661a710239Sad  */
6671a710239Sad static int
unionfs_copyfile_core(struct vnode * lvp,struct vnode * uvp,kauth_cred_t cred)6681a710239Sad unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
6691a710239Sad 		      kauth_cred_t cred)
6701a710239Sad {
6711a710239Sad 	int		error;
6721a710239Sad 	off_t		offset;
6731a710239Sad 	int		count;
6741a710239Sad 	int		bufoffset;
6751a710239Sad 	char           *buf;
6761a710239Sad 	struct uio	uio;
6771a710239Sad 	struct iovec	iov;
6781a710239Sad 
6791a710239Sad 	error = 0;
6801a710239Sad 	memset(&uio, 0, sizeof(uio));
6811a710239Sad 	UIO_SETUP_SYSSPACE(&uio);
6821a710239Sad 	uio.uio_offset = 0;
6831a710239Sad 
6841a710239Sad 	buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
6851a710239Sad 	while (error == 0) {
6861a710239Sad 		offset = uio.uio_offset;
6871a710239Sad 
6881a710239Sad 		uio.uio_iov = &iov;
6891a710239Sad 		uio.uio_iovcnt = 1;
6901a710239Sad 		iov.iov_base = buf;
6911a710239Sad 		iov.iov_len = MAXBSIZE;
6921a710239Sad 		uio.uio_resid = iov.iov_len;
6931a710239Sad 		uio.uio_rw = UIO_READ;
6941a710239Sad 
6951a710239Sad 		if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
6961a710239Sad 			break;
6971a710239Sad 		if ((count = MAXBSIZE - uio.uio_resid) == 0)
6981a710239Sad 			break;
6991a710239Sad 
7001a710239Sad 		bufoffset = 0;
7011a710239Sad 		while (bufoffset < count) {
7021a710239Sad 			uio.uio_iov = &iov;
7031a710239Sad 			uio.uio_iovcnt = 1;
7041a710239Sad 			iov.iov_base = buf + bufoffset;
7051a710239Sad 			iov.iov_len = count - bufoffset;
7061a710239Sad 			uio.uio_offset = offset + bufoffset;
7071a710239Sad 			uio.uio_resid = iov.iov_len;
7081a710239Sad 			uio.uio_rw = UIO_WRITE;
7091a710239Sad 
7101a710239Sad 			if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
7111a710239Sad 				break;
7121a710239Sad 
7131a710239Sad 			bufoffset += (count - bufoffset) - uio.uio_resid;
7141a710239Sad 		}
7151a710239Sad 
7161a710239Sad 		uio.uio_offset = offset + bufoffset;
7171a710239Sad 	}
7181a710239Sad 
7191a710239Sad 	kmem_free(buf, MAXBSIZE);
7201a710239Sad 
7211a710239Sad 	return (error);
7221a710239Sad }
7231a710239Sad 
7241a710239Sad /*
7251a710239Sad  * Copy file from lower to upper.
7261a710239Sad  *
7271a710239Sad  * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
7281a710239Sad  * docopy.
7291a710239Sad  *
7301a710239Sad  * If no error returned, unp will be updated.
7311a710239Sad  */
7321a710239Sad int
unionfs_copyfile(struct unionfs_node * unp,int docopy,kauth_cred_t cred)7331a710239Sad unionfs_copyfile(struct unionfs_node *unp, int docopy, kauth_cred_t cred)
7341a710239Sad {
7351a710239Sad 	int		error;
7361a710239Sad 	struct vnode   *udvp;
7371a710239Sad 	struct vnode   *lvp;
7381a710239Sad 	struct vnode   *uvp;
7391a710239Sad 	struct vattr	uva;
7401a710239Sad 
7411a710239Sad 	lvp = unp->un_lowervp;
7421a710239Sad 	uvp = NULLVP;
7431a710239Sad 
7441a710239Sad 	if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
7451a710239Sad 		return (EROFS);
7461a710239Sad 	if (unp->un_dvp == NULLVP)
7471a710239Sad 		return (EINVAL);
7481a710239Sad 	if (unp->un_uppervp != NULLVP)
7491a710239Sad 		return (EEXIST);
7501a710239Sad 	udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
7511a710239Sad 	if (udvp == NULLVP)
7521a710239Sad 		return (EROFS);
7531a710239Sad 	if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
7541a710239Sad 		return (EROFS);
7551a710239Sad 
7561a710239Sad 	error = VOP_ACCESS(lvp, VREAD, cred);
7571a710239Sad 	if (error != 0)
7581a710239Sad 		return (error);
7591a710239Sad 
7601a710239Sad 	error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva);
7611a710239Sad 	if (error != 0)
7621a710239Sad 		return (error);
7631a710239Sad 
7641a710239Sad 	if (docopy != 0) {
7651a710239Sad 		error = VOP_OPEN(lvp, FREAD, cred);
7661a710239Sad 		if (error == 0) {
7671a710239Sad 			error = unionfs_copyfile_core(lvp, uvp, cred);
7681a710239Sad 			VOP_CLOSE(lvp, FREAD, cred);
7691a710239Sad 		}
7701a710239Sad 	}
7711a710239Sad 	VOP_CLOSE(uvp, FWRITE, cred);
7721a710239Sad 	uvp->v_writecount--;
7731a710239Sad 
7741a710239Sad 	if (error == 0) {
7751a710239Sad 		/* Reset the attributes. Ignore errors. */
7761a710239Sad 		uva.va_type = VNON;
7771a710239Sad 		VOP_SETATTR(uvp, &uva, cred);
7781a710239Sad 	}
7791a710239Sad 
7801a710239Sad 	unionfs_node_update(unp, uvp);
7811a710239Sad 
7821a710239Sad 	return (error);
7831a710239Sad }
7841a710239Sad 
7851a710239Sad /*
7861a710239Sad  * It checks whether vp can rmdir. (check empty)
7871a710239Sad  *
7881a710239Sad  * vp is unionfs vnode.
7891a710239Sad  * vp should be locked.
7901a710239Sad  */
7911a710239Sad int
unionfs_check_rmdir(struct vnode * vp,kauth_cred_t cred)7921a710239Sad unionfs_check_rmdir(struct vnode *vp, kauth_cred_t cred)
7931a710239Sad {
7941a710239Sad 	int		error;
7951a710239Sad 	int		eofflag;
7961a710239Sad 	int		lookuperr;
7971a710239Sad 	struct vnode   *uvp;
7981a710239Sad 	struct vnode   *lvp;
7991a710239Sad 	struct vnode   *tvp;
8001a710239Sad 	struct vattr	va;
8011a710239Sad 	struct componentname cn;
8021a710239Sad 	/*
8031a710239Sad 	 * The size of buf needs to be larger than DIRBLKSIZ.
8041a710239Sad 	 */
8051a710239Sad 	char		buf[256 * 6];
8061a710239Sad 	struct dirent  *dp;
8071a710239Sad 	struct dirent  *edp;
8081a710239Sad 	struct uio	uio;
8091a710239Sad 	struct iovec	iov;
8101a710239Sad 
8111a710239Sad 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
8121a710239Sad 
8131a710239Sad 	eofflag = 0;
8141a710239Sad 	uvp = UNIONFSVPTOUPPERVP(vp);
8151a710239Sad 	lvp = UNIONFSVPTOLOWERVP(vp);
8161a710239Sad 
8171a710239Sad 	/* check opaque */
8181a710239Sad 	if ((error = VOP_GETATTR(uvp, &va, cred)) != 0)
8191a710239Sad 		return (error);
8201a710239Sad 	if (va.va_flags & OPAQUE)
8211a710239Sad 		return (0);
8221a710239Sad 
8231a710239Sad 	/* open vnode */
8241a710239Sad 	if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred)) != 0)
8251a710239Sad 		return (error);
8261a710239Sad 	if ((error = VOP_OPEN(vp, FREAD, cred)) != 0)
8271a710239Sad 		return (error);
8281a710239Sad 
8291a710239Sad 	UIO_SETUP_SYSSPACE(&uio);
8301a710239Sad 	uio.uio_rw = UIO_READ;
8311a710239Sad 	uio.uio_offset = 0;
8321a710239Sad 
8331a710239Sad 	while (!error && !eofflag) {
8341a710239Sad 		iov.iov_base = buf;
8351a710239Sad 		iov.iov_len = sizeof(buf);
8361a710239Sad 		uio.uio_iov = &iov;
8371a710239Sad 		uio.uio_iovcnt = 1;
8381a710239Sad 		uio.uio_resid = iov.iov_len;
8391a710239Sad 
8401a710239Sad 		error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
8411a710239Sad 		if (error)
8421a710239Sad 			break;
8431a710239Sad 
8441a710239Sad 		edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
8451a710239Sad 		for (dp = (struct dirent*)buf; !error && dp < edp;
8461a710239Sad 		     dp = (struct dirent*)((char *)dp + dp->d_reclen)) {
8471a710239Sad 			if (dp->d_type == DT_WHT ||
8481a710239Sad 			    (dp->d_namlen == 1 && dp->d_name[0] == '.') ||
84935fb6474Scegger 			    (dp->d_namlen == 2 && !memcmp(dp->d_name, "..", 2)))
8501a710239Sad 				continue;
8511a710239Sad 
8521a710239Sad 			cn.cn_namelen = dp->d_namlen;
8531a710239Sad 			cn.cn_nameptr = dp->d_name;
8541a710239Sad 			cn.cn_nameiop = LOOKUP;
85514402d0fSdholland 			cn.cn_flags = (LOCKPARENT | LOCKLEAF | RDONLY | ISLASTCN);
8561a710239Sad 			cn.cn_cred = cred;
8571a710239Sad 
8581a710239Sad 			/*
8591a710239Sad 			 * check entry in lower.
8601a710239Sad 			 * Sometimes, readdir function returns
8611a710239Sad 			 * wrong entry.
8621a710239Sad 			 */
8631a710239Sad 			lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
8641a710239Sad 
8651a710239Sad 			if (!lookuperr)
8661a710239Sad 				vput(tvp);
8671a710239Sad 			else
8681a710239Sad 				continue; /* skip entry */
8691a710239Sad 
8701a710239Sad 			/*
8711a710239Sad 			 * check entry
8721a710239Sad 			 * If it has no exist/whiteout entry in upper,
8731a710239Sad 			 * directory is not empty.
8741a710239Sad 			 */
87514402d0fSdholland 			cn.cn_flags = (LOCKPARENT | LOCKLEAF | RDONLY | ISLASTCN);
8761a710239Sad 			lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
8771a710239Sad 
8781a710239Sad 			if (!lookuperr)
8791a710239Sad 				vput(tvp);
8801a710239Sad 
8811a710239Sad 			/* ignore exist or whiteout entry */
8821a710239Sad 			if (!lookuperr ||
8831a710239Sad 			    (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
8841a710239Sad 				continue;
8851a710239Sad 
8861a710239Sad 			error = ENOTEMPTY;
8871a710239Sad 		}
8881a710239Sad 	}
8891a710239Sad 
8901a710239Sad 	/* close vnode */
8911a710239Sad 	VOP_CLOSE(vp, FREAD, cred);
8921a710239Sad 
8931a710239Sad 	return (error);
8941a710239Sad }
8951a710239Sad 
8961a710239Sad #ifdef DIAGNOSTIC
8971a710239Sad 
8981a710239Sad struct vnode   *
unionfs_checkuppervp(struct vnode * vp,const char * fil,int lno)8991a710239Sad unionfs_checkuppervp(struct vnode *vp, const char *fil, int lno)
9001a710239Sad {
9011a710239Sad 	struct unionfs_node *unp;
9021a710239Sad 
9031a710239Sad 	unp = VTOUNIONFS(vp);
9041a710239Sad 
9051a710239Sad #ifdef notyet
9061a710239Sad 	if (vp->v_op != unionfs_vnodeop_p) {
9071a710239Sad 		printf("unionfs_checkuppervp: on non-unionfs-node.\n");
9081a710239Sad #ifdef KDB
9091a710239Sad 		kdb_enter(KDB_WHY_UNIONFS,
9101a710239Sad 		    "unionfs_checkuppervp: on non-unionfs-node.\n");
9111a710239Sad #endif
9121a710239Sad 		panic("unionfs_checkuppervp");
9131a710239Sad 	};
9141a710239Sad #endif
9151a710239Sad 	return (unp->un_uppervp);
9161a710239Sad }
9171a710239Sad 
9181a710239Sad struct vnode   *
unionfs_checklowervp(struct vnode * vp,const char * fil,int lno)9191a710239Sad unionfs_checklowervp(struct vnode *vp, const char *fil, int lno)
9201a710239Sad {
9211a710239Sad 	struct unionfs_node *unp;
9221a710239Sad 
9231a710239Sad 	unp = VTOUNIONFS(vp);
9241a710239Sad 
9251a710239Sad #ifdef notyet
9261a710239Sad 	if (vp->v_op != unionfs_vnodeop_p) {
9271a710239Sad 		printf("unionfs_checklowervp: on non-unionfs-node.\n");
9281a710239Sad #ifdef KDB
9291a710239Sad 		kdb_enter(KDB_WHY_UNIONFS,
9301a710239Sad 		    "unionfs_checklowervp: on non-unionfs-node.\n");
9311a710239Sad #endif
9321a710239Sad 		panic("unionfs_checklowervp");
9331a710239Sad 	};
9341a710239Sad #endif
9351a710239Sad 	return (unp->un_lowervp);
9361a710239Sad }
9371a710239Sad #endif
938