1d167cf6fSWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1994 Jan-Simon Pendry 3df8bae1dSRodney W. Grimes * Copyright (c) 1994 4df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 5d00947d8SCraig Rodrigues * Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc. 6d00947d8SCraig Rodrigues * Copyright (c) 2006 Daichi Goto <daichi@freebsd.org> 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 9df8bae1dSRodney W. Grimes * Jan-Simon Pendry. 10df8bae1dSRodney W. Grimes * 11df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 12df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 13df8bae1dSRodney W. Grimes * are met: 14df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 16df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 18df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 19df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 20df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 21df8bae1dSRodney W. Grimes * without specific prior written permission. 22df8bae1dSRodney W. Grimes * 23df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33df8bae1dSRodney W. Grimes * SUCH DAMAGE. 34df8bae1dSRodney W. Grimes * 35996c772fSJohn Dyson * @(#)union_subr.c 8.20 (Berkeley) 5/20/95 36c3aac50fSPeter Wemm * $FreeBSD$ 37df8bae1dSRodney W. Grimes */ 38df8bae1dSRodney W. Grimes 39df8bae1dSRodney W. Grimes #include <sys/param.h> 40df8bae1dSRodney W. Grimes #include <sys/systm.h> 41fb919e4dSMark Murray #include <sys/kernel.h> 42fb919e4dSMark Murray #include <sys/lock.h> 432178ff8bSJohn Baldwin #include <sys/mutex.h> 44d00947d8SCraig Rodrigues #include <sys/malloc.h> 45d00947d8SCraig Rodrigues #include <sys/mount.h> 46fb919e4dSMark Murray #include <sys/namei.h> 47d00947d8SCraig Rodrigues #include <sys/proc.h> 48fb919e4dSMark Murray #include <sys/vnode.h> 49d00947d8SCraig Rodrigues #include <sys/dirent.h> 50d00947d8SCraig Rodrigues #include <sys/fcntl.h> 51d00947d8SCraig Rodrigues #include <sys/filedesc.h> 52d00947d8SCraig Rodrigues #include <sys/stat.h> 53d00947d8SCraig Rodrigues #include <sys/resourcevar.h> 54fb919e4dSMark Murray 55d00947d8SCraig Rodrigues #ifdef MAC 56d00947d8SCraig Rodrigues #include <sys/mac.h> 57d00947d8SCraig Rodrigues #endif 58d00947d8SCraig Rodrigues 598396dd9eSJeff Roberson #include <vm/uma.h> 60fb919e4dSMark Murray 6199d300a1SRuslan Ermilov #include <fs/unionfs/union.h> 62df8bae1dSRodney W. Grimes 63d00947d8SCraig Rodrigues MALLOC_DEFINE(M_UNIONFSNODE, "UNIONFS node", "UNIONFS vnode private part"); 64d00947d8SCraig Rodrigues MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part"); 65df8bae1dSRodney W. Grimes 66d00947d8SCraig Rodrigues /* 67dc2dd185SDaichi GOTO * Initialize 68d00947d8SCraig Rodrigues */ 69df8bae1dSRodney W. Grimes int 70d00947d8SCraig Rodrigues unionfs_init(struct vfsconf *vfsp) 71df8bae1dSRodney W. Grimes { 72d00947d8SCraig Rodrigues UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */ 7326f9a767SRodney W. Grimes return (0); 74df8bae1dSRodney W. Grimes } 75df8bae1dSRodney W. Grimes 76d00947d8SCraig Rodrigues /* 77dc2dd185SDaichi GOTO * Uninitialize 78d00947d8SCraig Rodrigues */ 79d00947d8SCraig Rodrigues int 80d00947d8SCraig Rodrigues unionfs_uninit(struct vfsconf *vfsp) 81df8bae1dSRodney W. Grimes { 82df8bae1dSRodney W. Grimes return (0); 83df8bae1dSRodney W. Grimes } 84df8bae1dSRodney W. Grimes 85d00947d8SCraig Rodrigues /* 86d00947d8SCraig Rodrigues * Make a new or get existing unionfs node. 872a31267eSMatthew Dillon * 88d00947d8SCraig Rodrigues * uppervp and lowervp should be unlocked. Because if new unionfs vnode is 89d00947d8SCraig Rodrigues * locked, uppervp or lowervp is locked too. In order to prevent dead lock, 90d00947d8SCraig Rodrigues * you should not lock plurality simultaneously. 91df8bae1dSRodney W. Grimes */ 92d00947d8SCraig Rodrigues int 93d00947d8SCraig Rodrigues unionfs_nodeget(struct mount *mp, struct vnode *uppervp, 94d00947d8SCraig Rodrigues struct vnode *lowervp, struct vnode *dvp, 95d00947d8SCraig Rodrigues struct vnode **vpp, struct componentname *cnp, 96d00947d8SCraig Rodrigues struct thread *td) 97d00947d8SCraig Rodrigues { 98d00947d8SCraig Rodrigues struct unionfs_mount *ump; 99d00947d8SCraig Rodrigues struct unionfs_node *unp; 100d00947d8SCraig Rodrigues struct vnode *vp; 101d00947d8SCraig Rodrigues int error; 102d00947d8SCraig Rodrigues int lkflags; 103d00947d8SCraig Rodrigues char *path; 104df8bae1dSRodney W. Grimes 105d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(mp); 106d00947d8SCraig Rodrigues lkflags = (cnp ? cnp->cn_lkflags : 0); 107dc2dd185SDaichi GOTO path = (cnp ? cnp->cn_nameptr : NULL); 1082a31267eSMatthew Dillon 109d00947d8SCraig Rodrigues if (uppervp == NULLVP && lowervp == NULLVP) 110d00947d8SCraig Rodrigues panic("unionfs_nodeget: upper and lower is null"); 111d00947d8SCraig Rodrigues 112d00947d8SCraig Rodrigues /* If it has no ISLASTCN flag, path check is skipped. */ 113dc2dd185SDaichi GOTO if (cnp && !(cnp->cn_flags & ISLASTCN)) 114d00947d8SCraig Rodrigues path = NULL; 115d00947d8SCraig Rodrigues 116d00947d8SCraig Rodrigues if ((uppervp == NULLVP || ump->um_uppervp != uppervp) || 117d00947d8SCraig Rodrigues (lowervp == NULLVP || ump->um_lowervp != lowervp)) { 118d00947d8SCraig Rodrigues if (dvp == NULLVP) 119d00947d8SCraig Rodrigues return (EINVAL); 120d00947d8SCraig Rodrigues } 121d00947d8SCraig Rodrigues 122df8bae1dSRodney W. Grimes /* 123d00947d8SCraig Rodrigues * Do the MALLOC before the getnewvnode since doing so afterward 124d00947d8SCraig Rodrigues * might cause a bogus v_data pointer to get dereferenced elsewhere 125d00947d8SCraig Rodrigues * if MALLOC should block. 126df8bae1dSRodney W. Grimes */ 127d00947d8SCraig Rodrigues MALLOC(unp, struct unionfs_node *, sizeof(struct unionfs_node), 128d00947d8SCraig Rodrigues M_UNIONFSNODE, M_WAITOK | M_ZERO); 129d00947d8SCraig Rodrigues 130d00947d8SCraig Rodrigues error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp); 131dc2dd185SDaichi GOTO if (error != 0) { 132d00947d8SCraig Rodrigues FREE(unp, M_UNIONFSNODE); 133d00947d8SCraig Rodrigues return (error); 134d00947d8SCraig Rodrigues } 13561b9d89fSTor Egge error = insmntque(vp, mp); /* XXX: Too early for mpsafe fs */ 13661b9d89fSTor Egge if (error != 0) { 13761b9d89fSTor Egge FREE(unp, M_UNIONFSNODE); 13861b9d89fSTor Egge return (error); 13961b9d89fSTor Egge } 140d00947d8SCraig Rodrigues if (dvp != NULLVP) 141d00947d8SCraig Rodrigues vref(dvp); 142d00947d8SCraig Rodrigues if (uppervp != NULLVP) 143d00947d8SCraig Rodrigues vref(uppervp); 144d00947d8SCraig Rodrigues if (lowervp != NULLVP) 145d00947d8SCraig Rodrigues vref(lowervp); 146d00947d8SCraig Rodrigues 147d00947d8SCraig Rodrigues unp->un_vnode = vp; 148d00947d8SCraig Rodrigues unp->un_uppervp = uppervp; 149d00947d8SCraig Rodrigues unp->un_lowervp = lowervp; 150d00947d8SCraig Rodrigues unp->un_dvp = dvp; 151d00947d8SCraig Rodrigues if (uppervp != NULLVP) 152d00947d8SCraig Rodrigues vp->v_vnlock = uppervp->v_vnlock; 153d00947d8SCraig Rodrigues else 154d00947d8SCraig Rodrigues vp->v_vnlock = lowervp->v_vnlock; 155d00947d8SCraig Rodrigues 156dc2dd185SDaichi GOTO if (path != NULL) { 157d00947d8SCraig Rodrigues unp->un_path = (char *) 158d00947d8SCraig Rodrigues malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO); 159d00947d8SCraig Rodrigues bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen); 160d00947d8SCraig Rodrigues unp->un_path[cnp->cn_namelen] = '\0'; 161d00947d8SCraig Rodrigues } 162d00947d8SCraig Rodrigues vp->v_type = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type); 163d00947d8SCraig Rodrigues vp->v_data = unp; 164d00947d8SCraig Rodrigues 165d00947d8SCraig Rodrigues if ((uppervp != NULLVP && ump->um_uppervp == uppervp) && 166d00947d8SCraig Rodrigues (lowervp != NULLVP && ump->um_lowervp == lowervp)) 167d00947d8SCraig Rodrigues vp->v_vflag |= VV_ROOT; 168d00947d8SCraig Rodrigues 169d00947d8SCraig Rodrigues if (lkflags & LK_TYPE_MASK) 170cb05b60aSAttilio Rao vn_lock(vp, lkflags | LK_RETRY); 171df8bae1dSRodney W. Grimes 172d00947d8SCraig Rodrigues *vpp = vp; 173d00947d8SCraig Rodrigues 174d00947d8SCraig Rodrigues return (0); 175996c772fSJohn Dyson } 176df8bae1dSRodney W. Grimes 1772a31267eSMatthew Dillon /* 178dc2dd185SDaichi GOTO * Clean up the unionfs node. 1792a31267eSMatthew Dillon */ 180d00947d8SCraig Rodrigues void 181dc2dd185SDaichi GOTO unionfs_noderem(struct vnode *vp, struct thread *td) 182d00947d8SCraig Rodrigues { 183d00947d8SCraig Rodrigues int vfslocked; 184d00947d8SCraig Rodrigues struct unionfs_node *unp; 185acc4bab1SCraig Rodrigues struct unionfs_node_status *unsp, *unsp_tmp; 186d00947d8SCraig Rodrigues struct vnode *lvp; 187d00947d8SCraig Rodrigues struct vnode *uvp; 1882a31267eSMatthew Dillon 1892a31267eSMatthew Dillon /* 190d00947d8SCraig Rodrigues * Use the interlock to protect the clearing of v_data to 191d00947d8SCraig Rodrigues * prevent faults in unionfs_lock(). 1922a31267eSMatthew Dillon */ 193d00947d8SCraig Rodrigues VI_LOCK(vp); 194d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 195d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 196d00947d8SCraig Rodrigues uvp = unp->un_uppervp; 197d00947d8SCraig Rodrigues unp->un_lowervp = unp->un_uppervp = NULLVP; 198d00947d8SCraig Rodrigues 199d00947d8SCraig Rodrigues vp->v_vnlock = &(vp->v_lock); 200d00947d8SCraig Rodrigues vp->v_data = NULL; 201d00947d8SCraig Rodrigues lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_INTERLOCK, VI_MTX(vp), td); 202d00947d8SCraig Rodrigues if (lvp != NULLVP) 203d00947d8SCraig Rodrigues VOP_UNLOCK(lvp, 0, td); 204d00947d8SCraig Rodrigues if (uvp != NULLVP) 205d00947d8SCraig Rodrigues VOP_UNLOCK(uvp, 0, td); 206d00947d8SCraig Rodrigues vp->v_object = NULL; 207d00947d8SCraig Rodrigues 208d00947d8SCraig Rodrigues if (lvp != NULLVP) { 209d00947d8SCraig Rodrigues vfslocked = VFS_LOCK_GIANT(lvp->v_mount); 210d00947d8SCraig Rodrigues vrele(lvp); 211d00947d8SCraig Rodrigues VFS_UNLOCK_GIANT(vfslocked); 212d00947d8SCraig Rodrigues } 213d00947d8SCraig Rodrigues if (uvp != NULLVP) { 214d00947d8SCraig Rodrigues vfslocked = VFS_LOCK_GIANT(uvp->v_mount); 215d00947d8SCraig Rodrigues vrele(uvp); 216d00947d8SCraig Rodrigues VFS_UNLOCK_GIANT(vfslocked); 217d00947d8SCraig Rodrigues } 218d00947d8SCraig Rodrigues if (unp->un_dvp != NULLVP) { 219d00947d8SCraig Rodrigues vfslocked = VFS_LOCK_GIANT(unp->un_dvp->v_mount); 220d00947d8SCraig Rodrigues vrele(unp->un_dvp); 221d00947d8SCraig Rodrigues VFS_UNLOCK_GIANT(vfslocked); 222d00947d8SCraig Rodrigues unp->un_dvp = NULLVP; 223d00947d8SCraig Rodrigues } 224d00947d8SCraig Rodrigues if (unp->un_path) { 225d00947d8SCraig Rodrigues free(unp->un_path, M_UNIONFSPATH); 226d00947d8SCraig Rodrigues unp->un_path = NULL; 227d00947d8SCraig Rodrigues } 228acc4bab1SCraig Rodrigues 229acc4bab1SCraig Rodrigues LIST_FOREACH_SAFE(unsp, &(unp->un_unshead), uns_list, unsp_tmp) { 230d00947d8SCraig Rodrigues LIST_REMOVE(unsp, uns_list); 231d00947d8SCraig Rodrigues free(unsp, M_TEMP); 232d00947d8SCraig Rodrigues } 233d00947d8SCraig Rodrigues FREE(unp, M_UNIONFSNODE); 234df8bae1dSRodney W. Grimes } 235df8bae1dSRodney W. Grimes 236d00947d8SCraig Rodrigues /* 237d00947d8SCraig Rodrigues * Get the unionfs node status. 238d00947d8SCraig Rodrigues * You need exclusive lock this vnode. 239d00947d8SCraig Rodrigues */ 240d00947d8SCraig Rodrigues void 241d00947d8SCraig Rodrigues unionfs_get_node_status(struct unionfs_node *unp, struct thread *td, 242d00947d8SCraig Rodrigues struct unionfs_node_status **unspp) 243d00947d8SCraig Rodrigues { 244d00947d8SCraig Rodrigues struct unionfs_node_status *unsp; 245df8bae1dSRodney W. Grimes 246d00947d8SCraig Rodrigues KASSERT(NULL != unspp, ("null pointer")); 247d00947d8SCraig Rodrigues ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status"); 2482a31267eSMatthew Dillon 249d00947d8SCraig Rodrigues LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) { 250d00947d8SCraig Rodrigues if (unsp->uns_tid == td->td_tid) { 251d00947d8SCraig Rodrigues *unspp = unsp; 252d00947d8SCraig Rodrigues return; 253d00947d8SCraig Rodrigues } 254d00947d8SCraig Rodrigues } 2552a31267eSMatthew Dillon 256d00947d8SCraig Rodrigues /* create a new unionfs node status */ 257d00947d8SCraig Rodrigues MALLOC(unsp, struct unionfs_node_status *, 258d00947d8SCraig Rodrigues sizeof(struct unionfs_node_status), M_TEMP, M_WAITOK | M_ZERO); 2592a31267eSMatthew Dillon 260d00947d8SCraig Rodrigues unsp->uns_tid = td->td_tid; 261d00947d8SCraig Rodrigues LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list); 2622a31267eSMatthew Dillon 263d00947d8SCraig Rodrigues *unspp = unsp; 264d00947d8SCraig Rodrigues } 265d00947d8SCraig Rodrigues 266d00947d8SCraig Rodrigues /* 267d00947d8SCraig Rodrigues * Remove the unionfs node status, if you can. 268d00947d8SCraig Rodrigues * You need exclusive lock this vnode. 269d00947d8SCraig Rodrigues */ 270d00947d8SCraig Rodrigues void 271d00947d8SCraig Rodrigues unionfs_tryrem_node_status(struct unionfs_node *unp, struct thread *td, 272d00947d8SCraig Rodrigues struct unionfs_node_status *unsp) 273d00947d8SCraig Rodrigues { 274d00947d8SCraig Rodrigues KASSERT(NULL != unsp, ("null pointer")); 275d00947d8SCraig Rodrigues ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status"); 276d00947d8SCraig Rodrigues 277d00947d8SCraig Rodrigues if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt) 278d00947d8SCraig Rodrigues return; 279d00947d8SCraig Rodrigues 280d00947d8SCraig Rodrigues LIST_REMOVE(unsp, uns_list); 281d00947d8SCraig Rodrigues free(unsp, M_TEMP); 282d00947d8SCraig Rodrigues } 283d00947d8SCraig Rodrigues 284d00947d8SCraig Rodrigues /* 285d00947d8SCraig Rodrigues * Create upper node attr. 286d00947d8SCraig Rodrigues */ 287d00947d8SCraig Rodrigues void 288d00947d8SCraig Rodrigues unionfs_create_uppervattr_core(struct unionfs_mount *ump, 289d00947d8SCraig Rodrigues struct vattr *lva, 290d00947d8SCraig Rodrigues struct vattr *uva, 291d00947d8SCraig Rodrigues struct thread *td) 292d00947d8SCraig Rodrigues { 293d00947d8SCraig Rodrigues VATTR_NULL(uva); 294d00947d8SCraig Rodrigues uva->va_type = lva->va_type; 295d00947d8SCraig Rodrigues uva->va_atime = lva->va_atime; 296d00947d8SCraig Rodrigues uva->va_mtime = lva->va_mtime; 297d00947d8SCraig Rodrigues uva->va_ctime = lva->va_ctime; 298d00947d8SCraig Rodrigues 299d00947d8SCraig Rodrigues switch (ump->um_copymode) { 300d00947d8SCraig Rodrigues case UNIONFS_TRANSPARENT: 301d00947d8SCraig Rodrigues uva->va_mode = lva->va_mode; 302d00947d8SCraig Rodrigues uva->va_uid = lva->va_uid; 303d00947d8SCraig Rodrigues uva->va_gid = lva->va_gid; 304d00947d8SCraig Rodrigues break; 305d00947d8SCraig Rodrigues case UNIONFS_MASQUERADE: 306d00947d8SCraig Rodrigues if (ump->um_uid == lva->va_uid) { 307d00947d8SCraig Rodrigues uva->va_mode = lva->va_mode & 077077; 308d00947d8SCraig Rodrigues uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700; 309d00947d8SCraig Rodrigues uva->va_uid = lva->va_uid; 310d00947d8SCraig Rodrigues uva->va_gid = lva->va_gid; 311df8bae1dSRodney W. Grimes } else { 312d00947d8SCraig Rodrigues uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile); 313d00947d8SCraig Rodrigues uva->va_uid = ump->um_uid; 314d00947d8SCraig Rodrigues uva->va_gid = ump->um_gid; 315d00947d8SCraig Rodrigues } 316d00947d8SCraig Rodrigues break; 317d00947d8SCraig Rodrigues default: /* UNIONFS_TRADITIONAL */ 3185e3f7694SRobert Watson FILEDESC_SLOCK(td->td_proc->p_fd); 319d00947d8SCraig Rodrigues uva->va_mode = 0777 & ~td->td_proc->p_fd->fd_cmask; 3205e3f7694SRobert Watson FILEDESC_SUNLOCK(td->td_proc->p_fd); 321d00947d8SCraig Rodrigues uva->va_uid = ump->um_uid; 322d00947d8SCraig Rodrigues uva->va_gid = ump->um_gid; 323d00947d8SCraig Rodrigues break; 324d00947d8SCraig Rodrigues } 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes 327d00947d8SCraig Rodrigues /* 328d00947d8SCraig Rodrigues * Create upper node attr. 329d00947d8SCraig Rodrigues */ 330d00947d8SCraig Rodrigues int 331d00947d8SCraig Rodrigues unionfs_create_uppervattr(struct unionfs_mount *ump, 332d00947d8SCraig Rodrigues struct vnode *lvp, 333d00947d8SCraig Rodrigues struct vattr *uva, 334d00947d8SCraig Rodrigues struct ucred *cred, 335d00947d8SCraig Rodrigues struct thread *td) 336d00947d8SCraig Rodrigues { 337d00947d8SCraig Rodrigues int error; 338d00947d8SCraig Rodrigues struct vattr lva; 339df8bae1dSRodney W. Grimes 340d00947d8SCraig Rodrigues if ((error = VOP_GETATTR(lvp, &lva, cred, td))) 341d00947d8SCraig Rodrigues return (error); 342d00947d8SCraig Rodrigues 343d00947d8SCraig Rodrigues unionfs_create_uppervattr_core(ump, &lva, uva, td); 344df8bae1dSRodney W. Grimes 345df8bae1dSRodney W. Grimes return (error); 346df8bae1dSRodney W. Grimes } 347df8bae1dSRodney W. Grimes 348d00947d8SCraig Rodrigues /* 349d00947d8SCraig Rodrigues * relookup 350d00947d8SCraig Rodrigues * 351d00947d8SCraig Rodrigues * dvp should be locked on entry and will be locked on return. 352d00947d8SCraig Rodrigues * 353d00947d8SCraig Rodrigues * If an error is returned, *vpp will be invalid, otherwise it will hold a 354d00947d8SCraig Rodrigues * locked, referenced vnode. If *vpp == dvp then remember that only one 355d00947d8SCraig Rodrigues * LK_EXCLUSIVE lock is held. 356d00947d8SCraig Rodrigues */ 357d00947d8SCraig Rodrigues static int 358d00947d8SCraig Rodrigues unionfs_relookup(struct vnode *dvp, struct vnode **vpp, 359d00947d8SCraig Rodrigues struct componentname *cnp, struct componentname *cn, 360d00947d8SCraig Rodrigues struct thread *td, char *path, int pathlen, u_long nameiop) 361df8bae1dSRodney W. Grimes { 362d00947d8SCraig Rodrigues int error; 363df8bae1dSRodney W. Grimes 364d00947d8SCraig Rodrigues cn->cn_namelen = pathlen; 365d00947d8SCraig Rodrigues cn->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 366d00947d8SCraig Rodrigues bcopy(path, cn->cn_pnbuf, pathlen); 367d00947d8SCraig Rodrigues cn->cn_pnbuf[pathlen] = '\0'; 368df8bae1dSRodney W. Grimes 369d00947d8SCraig Rodrigues cn->cn_nameiop = nameiop; 370d00947d8SCraig Rodrigues cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN); 371d00947d8SCraig Rodrigues cn->cn_lkflags = LK_EXCLUSIVE; 372d00947d8SCraig Rodrigues cn->cn_thread = td; 373d00947d8SCraig Rodrigues cn->cn_cred = cnp->cn_cred; 374df8bae1dSRodney W. Grimes 375d00947d8SCraig Rodrigues cn->cn_nameptr = cn->cn_pnbuf; 376d00947d8SCraig Rodrigues cn->cn_consume = cnp->cn_consume; 377df8bae1dSRodney W. Grimes 378d00947d8SCraig Rodrigues if (nameiop == DELETE) 379d00947d8SCraig Rodrigues cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART)); 380d00947d8SCraig Rodrigues else if (RENAME == nameiop) 381d00947d8SCraig Rodrigues cn->cn_flags |= (cnp->cn_flags & SAVESTART); 382d00947d8SCraig Rodrigues 383d00947d8SCraig Rodrigues vref(dvp); 384d00947d8SCraig Rodrigues VOP_UNLOCK(dvp, 0, td); 385d00947d8SCraig Rodrigues 386d00947d8SCraig Rodrigues if ((error = relookup(dvp, vpp, cn))) { 387d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn->cn_pnbuf); 388d00947d8SCraig Rodrigues cn->cn_flags &= ~HASBUF; 389cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 390d00947d8SCraig Rodrigues } else 391d00947d8SCraig Rodrigues vrele(dvp); 392d00947d8SCraig Rodrigues 393d00947d8SCraig Rodrigues return (error); 394df8bae1dSRodney W. Grimes } 395df8bae1dSRodney W. Grimes 396df8bae1dSRodney W. Grimes /* 397d00947d8SCraig Rodrigues * relookup for CREATE namei operation. 3982a31267eSMatthew Dillon * 399d00947d8SCraig Rodrigues * dvp is unionfs vnode. dvp should be locked. 400d00947d8SCraig Rodrigues * 401d00947d8SCraig Rodrigues * If it called 'unionfs_copyfile' function by unionfs_link etc, 402d00947d8SCraig Rodrigues * VOP_LOOKUP information is broken. 403d00947d8SCraig Rodrigues * So it need relookup in order to create link etc. 404d00947d8SCraig Rodrigues */ 405d00947d8SCraig Rodrigues int 406d00947d8SCraig Rodrigues unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp, 407d00947d8SCraig Rodrigues struct thread *td) 408d00947d8SCraig Rodrigues { 409d00947d8SCraig Rodrigues int error; 410d00947d8SCraig Rodrigues struct vnode *udvp; 411d00947d8SCraig Rodrigues struct vnode *vp; 412d00947d8SCraig Rodrigues struct componentname cn; 413d00947d8SCraig Rodrigues 414d00947d8SCraig Rodrigues udvp = UNIONFSVPTOUPPERVP(dvp); 415d00947d8SCraig Rodrigues vp = NULLVP; 416d00947d8SCraig Rodrigues 417d00947d8SCraig Rodrigues error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr, 418d00947d8SCraig Rodrigues strlen(cnp->cn_nameptr), CREATE); 419d00947d8SCraig Rodrigues if (error) 420d00947d8SCraig Rodrigues return (error); 421d00947d8SCraig Rodrigues 422d00947d8SCraig Rodrigues if (vp != NULLVP) { 423d00947d8SCraig Rodrigues if (udvp == vp) 424d00947d8SCraig Rodrigues vrele(vp); 425d00947d8SCraig Rodrigues else 426d00947d8SCraig Rodrigues vput(vp); 427d00947d8SCraig Rodrigues 428d00947d8SCraig Rodrigues error = EEXIST; 429d00947d8SCraig Rodrigues } 430d00947d8SCraig Rodrigues 431d00947d8SCraig Rodrigues if (cn.cn_flags & HASBUF) { 432d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn.cn_pnbuf); 433d00947d8SCraig Rodrigues cn.cn_flags &= ~HASBUF; 434d00947d8SCraig Rodrigues } 435d00947d8SCraig Rodrigues 436d00947d8SCraig Rodrigues if (!error) { 437d00947d8SCraig Rodrigues cn.cn_flags |= (cnp->cn_flags & HASBUF); 438d00947d8SCraig Rodrigues cnp->cn_flags = cn.cn_flags; 439d00947d8SCraig Rodrigues } 440d00947d8SCraig Rodrigues 441d00947d8SCraig Rodrigues return (error); 442d00947d8SCraig Rodrigues } 443d00947d8SCraig Rodrigues 444d00947d8SCraig Rodrigues /* 445d00947d8SCraig Rodrigues * relookup for DELETE namei operation. 446d00947d8SCraig Rodrigues * 447d00947d8SCraig Rodrigues * dvp is unionfs vnode. dvp should be locked. 448d00947d8SCraig Rodrigues */ 449d00947d8SCraig Rodrigues int 450d00947d8SCraig Rodrigues unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp, 451d00947d8SCraig Rodrigues struct thread *td) 452d00947d8SCraig Rodrigues { 453d00947d8SCraig Rodrigues int error; 454d00947d8SCraig Rodrigues struct vnode *udvp; 455d00947d8SCraig Rodrigues struct vnode *vp; 456d00947d8SCraig Rodrigues struct componentname cn; 457d00947d8SCraig Rodrigues 458d00947d8SCraig Rodrigues udvp = UNIONFSVPTOUPPERVP(dvp); 459d00947d8SCraig Rodrigues vp = NULLVP; 460d00947d8SCraig Rodrigues 461d00947d8SCraig Rodrigues error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr, 462d00947d8SCraig Rodrigues strlen(cnp->cn_nameptr), DELETE); 463d00947d8SCraig Rodrigues if (error) 464d00947d8SCraig Rodrigues return (error); 465d00947d8SCraig Rodrigues 466d00947d8SCraig Rodrigues if (vp == NULLVP) 467d00947d8SCraig Rodrigues error = ENOENT; 468d00947d8SCraig Rodrigues else { 469d00947d8SCraig Rodrigues if (udvp == vp) 470d00947d8SCraig Rodrigues vrele(vp); 471d00947d8SCraig Rodrigues else 472d00947d8SCraig Rodrigues vput(vp); 473d00947d8SCraig Rodrigues } 474d00947d8SCraig Rodrigues 475d00947d8SCraig Rodrigues if (cn.cn_flags & HASBUF) { 476d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn.cn_pnbuf); 477d00947d8SCraig Rodrigues cn.cn_flags &= ~HASBUF; 478d00947d8SCraig Rodrigues } 479d00947d8SCraig Rodrigues 480d00947d8SCraig Rodrigues if (!error) { 481d00947d8SCraig Rodrigues cn.cn_flags |= (cnp->cn_flags & HASBUF); 482d00947d8SCraig Rodrigues cnp->cn_flags = cn.cn_flags; 483d00947d8SCraig Rodrigues } 484d00947d8SCraig Rodrigues 485d00947d8SCraig Rodrigues return (error); 486d00947d8SCraig Rodrigues } 487d00947d8SCraig Rodrigues 488d00947d8SCraig Rodrigues /* 489d00947d8SCraig Rodrigues * relookup for RENAME namei operation. 490d00947d8SCraig Rodrigues * 491d00947d8SCraig Rodrigues * dvp is unionfs vnode. dvp should be locked. 492d00947d8SCraig Rodrigues */ 493d00947d8SCraig Rodrigues int 494d00947d8SCraig Rodrigues unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp, 495d00947d8SCraig Rodrigues struct thread *td) 496d00947d8SCraig Rodrigues { 497d00947d8SCraig Rodrigues int error; 498d00947d8SCraig Rodrigues struct vnode *udvp; 499d00947d8SCraig Rodrigues struct vnode *vp; 500d00947d8SCraig Rodrigues struct componentname cn; 501d00947d8SCraig Rodrigues 502d00947d8SCraig Rodrigues udvp = UNIONFSVPTOUPPERVP(dvp); 503d00947d8SCraig Rodrigues vp = NULLVP; 504d00947d8SCraig Rodrigues 505d00947d8SCraig Rodrigues error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr, 506d00947d8SCraig Rodrigues strlen(cnp->cn_nameptr), RENAME); 507d00947d8SCraig Rodrigues if (error) 508d00947d8SCraig Rodrigues return (error); 509d00947d8SCraig Rodrigues 510d00947d8SCraig Rodrigues if (vp != NULLVP) { 511d00947d8SCraig Rodrigues if (udvp == vp) 512d00947d8SCraig Rodrigues vrele(vp); 513d00947d8SCraig Rodrigues else 514d00947d8SCraig Rodrigues vput(vp); 515d00947d8SCraig Rodrigues } 516d00947d8SCraig Rodrigues 517d00947d8SCraig Rodrigues if (cn.cn_flags & HASBUF) { 518d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn.cn_pnbuf); 519d00947d8SCraig Rodrigues cn.cn_flags &= ~HASBUF; 520d00947d8SCraig Rodrigues } 521d00947d8SCraig Rodrigues 522d00947d8SCraig Rodrigues if (!error) { 523d00947d8SCraig Rodrigues cn.cn_flags |= (cnp->cn_flags & HASBUF); 524d00947d8SCraig Rodrigues cnp->cn_flags = cn.cn_flags; 525d00947d8SCraig Rodrigues } 526d00947d8SCraig Rodrigues 527d00947d8SCraig Rodrigues return (error); 528d00947d8SCraig Rodrigues 529d00947d8SCraig Rodrigues } 530d00947d8SCraig Rodrigues 531d00947d8SCraig Rodrigues /* 532d00947d8SCraig Rodrigues * Update the unionfs_node. 533d00947d8SCraig Rodrigues * 534d00947d8SCraig Rodrigues * uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the 535d00947d8SCraig Rodrigues * uvp's lock and lower's lock will be unlocked. 536d00947d8SCraig Rodrigues */ 537d00947d8SCraig Rodrigues static void 538d00947d8SCraig Rodrigues unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp, 539d00947d8SCraig Rodrigues struct thread *td) 540d00947d8SCraig Rodrigues { 541d00947d8SCraig Rodrigues int count, lockcnt; 542d00947d8SCraig Rodrigues struct vnode *vp; 543d00947d8SCraig Rodrigues struct vnode *lvp; 544d00947d8SCraig Rodrigues 545d00947d8SCraig Rodrigues vp = UNIONFSTOV(unp); 546d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 547d00947d8SCraig Rodrigues 548d00947d8SCraig Rodrigues /* 549d00947d8SCraig Rodrigues * lock update 550d00947d8SCraig Rodrigues */ 551d00947d8SCraig Rodrigues VI_LOCK(vp); 552d00947d8SCraig Rodrigues unp->un_uppervp = uvp; 553d00947d8SCraig Rodrigues vp->v_vnlock = uvp->v_vnlock; 554d00947d8SCraig Rodrigues lockcnt = lvp->v_vnlock->lk_exclusivecount; 555d00947d8SCraig Rodrigues if (lockcnt <= 0) 556d00947d8SCraig Rodrigues panic("unionfs: no exclusive lock"); 557d00947d8SCraig Rodrigues VI_UNLOCK(vp); 558d00947d8SCraig Rodrigues for (count = 1; count < lockcnt; count++) 559cb05b60aSAttilio Rao vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY); 560d00947d8SCraig Rodrigues } 561d00947d8SCraig Rodrigues 562d00947d8SCraig Rodrigues /* 563d00947d8SCraig Rodrigues * Create a new shadow dir. 564d00947d8SCraig Rodrigues * 565d00947d8SCraig Rodrigues * udvp should be locked on entry and will be locked on return. 566d00947d8SCraig Rodrigues * 567d00947d8SCraig Rodrigues * If no error returned, unp will be updated. 568d00947d8SCraig Rodrigues */ 569d00947d8SCraig Rodrigues int 570d00947d8SCraig Rodrigues unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp, 571d00947d8SCraig Rodrigues struct unionfs_node *unp, struct componentname *cnp, 572d00947d8SCraig Rodrigues struct thread *td) 573d00947d8SCraig Rodrigues { 574d00947d8SCraig Rodrigues int error; 575d00947d8SCraig Rodrigues struct vnode *lvp; 576d00947d8SCraig Rodrigues struct vnode *uvp; 577d00947d8SCraig Rodrigues struct vattr va; 578d00947d8SCraig Rodrigues struct vattr lva; 579d00947d8SCraig Rodrigues struct componentname cn; 580d00947d8SCraig Rodrigues struct mount *mp; 581d00947d8SCraig Rodrigues struct ucred *cred; 582d00947d8SCraig Rodrigues struct ucred *credbk; 583d00947d8SCraig Rodrigues struct uidinfo *rootinfo; 584d00947d8SCraig Rodrigues 585d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 586d00947d8SCraig Rodrigues return (EEXIST); 587d00947d8SCraig Rodrigues 588d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 589d00947d8SCraig Rodrigues uvp = NULLVP; 590d00947d8SCraig Rodrigues credbk = cnp->cn_cred; 591d00947d8SCraig Rodrigues 592d00947d8SCraig Rodrigues /* Authority change to root */ 593d00947d8SCraig Rodrigues rootinfo = uifind((uid_t)0); 594d00947d8SCraig Rodrigues cred = crdup(cnp->cn_cred); 595d00947d8SCraig Rodrigues chgproccnt(cred->cr_ruidinfo, 1, 0); 596d00947d8SCraig Rodrigues change_euid(cred, rootinfo); 597d00947d8SCraig Rodrigues change_ruid(cred, rootinfo); 598d00947d8SCraig Rodrigues change_svuid(cred, (uid_t)0); 599d00947d8SCraig Rodrigues uifree(rootinfo); 600d00947d8SCraig Rodrigues cnp->cn_cred = cred; 601d00947d8SCraig Rodrigues 602d00947d8SCraig Rodrigues memset(&cn, 0, sizeof(cn)); 603d00947d8SCraig Rodrigues 604d00947d8SCraig Rodrigues if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred, td))) 605d00947d8SCraig Rodrigues goto unionfs_mkshadowdir_abort; 606d00947d8SCraig Rodrigues 607d00947d8SCraig Rodrigues if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, td, cnp->cn_nameptr, cnp->cn_namelen, CREATE))) 608d00947d8SCraig Rodrigues goto unionfs_mkshadowdir_abort; 609d00947d8SCraig Rodrigues if (uvp != NULLVP) { 610d00947d8SCraig Rodrigues if (udvp == uvp) 611d00947d8SCraig Rodrigues vrele(uvp); 612d00947d8SCraig Rodrigues else 613d00947d8SCraig Rodrigues vput(uvp); 614d00947d8SCraig Rodrigues 615d00947d8SCraig Rodrigues error = EEXIST; 616d00947d8SCraig Rodrigues goto unionfs_mkshadowdir_free_out; 617d00947d8SCraig Rodrigues } 618d00947d8SCraig Rodrigues 619d00947d8SCraig Rodrigues if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH))) 620d00947d8SCraig Rodrigues goto unionfs_mkshadowdir_free_out; 621d00947d8SCraig Rodrigues if ((error = VOP_LEASE(udvp, td, cn.cn_cred, LEASE_WRITE))) { 622d00947d8SCraig Rodrigues vn_finished_write(mp); 623d00947d8SCraig Rodrigues goto unionfs_mkshadowdir_free_out; 624d00947d8SCraig Rodrigues } 625d00947d8SCraig Rodrigues unionfs_create_uppervattr_core(ump, &lva, &va, td); 626d00947d8SCraig Rodrigues 627d00947d8SCraig Rodrigues error = VOP_MKDIR(udvp, &uvp, &cn, &va); 628d00947d8SCraig Rodrigues 629d00947d8SCraig Rodrigues if (!error) { 630d00947d8SCraig Rodrigues unionfs_node_update(unp, uvp, td); 631d00947d8SCraig Rodrigues 632d00947d8SCraig Rodrigues /* 633d00947d8SCraig Rodrigues * XXX The bug which cannot set uid/gid was corrected. 634d00947d8SCraig Rodrigues * Ignore errors. 635d00947d8SCraig Rodrigues */ 636d00947d8SCraig Rodrigues va.va_type = VNON; 637d00947d8SCraig Rodrigues VOP_SETATTR(uvp, &va, cn.cn_cred, td); 638d00947d8SCraig Rodrigues } 639d00947d8SCraig Rodrigues vn_finished_write(mp); 640d00947d8SCraig Rodrigues 641d00947d8SCraig Rodrigues unionfs_mkshadowdir_free_out: 642d00947d8SCraig Rodrigues if (cn.cn_flags & HASBUF) { 643d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn.cn_pnbuf); 644d00947d8SCraig Rodrigues cn.cn_flags &= ~HASBUF; 645d00947d8SCraig Rodrigues } 646d00947d8SCraig Rodrigues 647d00947d8SCraig Rodrigues unionfs_mkshadowdir_abort: 648d00947d8SCraig Rodrigues cnp->cn_cred = credbk; 649d00947d8SCraig Rodrigues chgproccnt(cred->cr_ruidinfo, -1, 0); 650d00947d8SCraig Rodrigues crfree(cred); 651d00947d8SCraig Rodrigues 652d00947d8SCraig Rodrigues return (error); 653d00947d8SCraig Rodrigues } 654d00947d8SCraig Rodrigues 655d00947d8SCraig Rodrigues /* 656d00947d8SCraig Rodrigues * Create a new whiteout. 657d00947d8SCraig Rodrigues * 658d00947d8SCraig Rodrigues * dvp should be locked on entry and will be locked on return. 659d00947d8SCraig Rodrigues */ 660d00947d8SCraig Rodrigues int 661d00947d8SCraig Rodrigues unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp, 662d00947d8SCraig Rodrigues struct thread *td, char *path) 663d00947d8SCraig Rodrigues { 664d00947d8SCraig Rodrigues int error; 665d00947d8SCraig Rodrigues struct vnode *wvp; 666d00947d8SCraig Rodrigues struct componentname cn; 667d00947d8SCraig Rodrigues struct mount *mp; 668d00947d8SCraig Rodrigues 669d00947d8SCraig Rodrigues if (path == NULL) 670d00947d8SCraig Rodrigues path = cnp->cn_nameptr; 671d00947d8SCraig Rodrigues 672d00947d8SCraig Rodrigues wvp = NULLVP; 673d00947d8SCraig Rodrigues if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, td, path, strlen(path), CREATE))) 674d00947d8SCraig Rodrigues return (error); 675d00947d8SCraig Rodrigues if (wvp != NULLVP) { 676d00947d8SCraig Rodrigues if (cn.cn_flags & HASBUF) { 677d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn.cn_pnbuf); 678d00947d8SCraig Rodrigues cn.cn_flags &= ~HASBUF; 679d00947d8SCraig Rodrigues } 680d00947d8SCraig Rodrigues if (dvp == wvp) 681d00947d8SCraig Rodrigues vrele(wvp); 682d00947d8SCraig Rodrigues else 683d00947d8SCraig Rodrigues vput(wvp); 684d00947d8SCraig Rodrigues 685d00947d8SCraig Rodrigues return (EEXIST); 686d00947d8SCraig Rodrigues } 687d00947d8SCraig Rodrigues 688d00947d8SCraig Rodrigues if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH))) 689d00947d8SCraig Rodrigues goto unionfs_mkwhiteout_free_out; 690d00947d8SCraig Rodrigues if (!(error = VOP_LEASE(dvp, td, td->td_ucred, LEASE_WRITE))) 691d00947d8SCraig Rodrigues error = VOP_WHITEOUT(dvp, &cn, CREATE); 692d00947d8SCraig Rodrigues 693d00947d8SCraig Rodrigues vn_finished_write(mp); 694d00947d8SCraig Rodrigues 695d00947d8SCraig Rodrigues unionfs_mkwhiteout_free_out: 696d00947d8SCraig Rodrigues if (cn.cn_flags & HASBUF) { 697d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn.cn_pnbuf); 698d00947d8SCraig Rodrigues cn.cn_flags &= ~HASBUF; 699d00947d8SCraig Rodrigues } 700d00947d8SCraig Rodrigues 701d00947d8SCraig Rodrigues return (error); 702d00947d8SCraig Rodrigues } 703d00947d8SCraig Rodrigues 704d00947d8SCraig Rodrigues /* 705d00947d8SCraig Rodrigues * Create a new vnode for create a new shadow file. 706d00947d8SCraig Rodrigues * 707d00947d8SCraig Rodrigues * If an error is returned, *vpp will be invalid, otherwise it will hold a 708d00947d8SCraig Rodrigues * locked, referenced and opened vnode. 709d00947d8SCraig Rodrigues * 710d00947d8SCraig Rodrigues * unp is never updated. 711df8bae1dSRodney W. Grimes */ 71280b301c3SPoul-Henning Kamp static int 713d00947d8SCraig Rodrigues unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp, 714d00947d8SCraig Rodrigues struct unionfs_node *unp, struct vattr *uvap, 715d00947d8SCraig Rodrigues struct thread *td) 716df8bae1dSRodney W. Grimes { 717d00947d8SCraig Rodrigues struct unionfs_mount *ump; 718d00947d8SCraig Rodrigues struct vnode *vp; 719d00947d8SCraig Rodrigues struct vnode *lvp; 720d00947d8SCraig Rodrigues struct ucred *cred; 721d00947d8SCraig Rodrigues struct vattr lva; 722d00947d8SCraig Rodrigues int fmode; 723d00947d8SCraig Rodrigues int error; 724d00947d8SCraig Rodrigues struct componentname cn; 725d00947d8SCraig Rodrigues 726d00947d8SCraig Rodrigues ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount); 727d00947d8SCraig Rodrigues vp = NULLVP; 728d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 729d00947d8SCraig Rodrigues cred = td->td_ucred; 730d00947d8SCraig Rodrigues fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL); 731d00947d8SCraig Rodrigues error = 0; 732d00947d8SCraig Rodrigues 733d00947d8SCraig Rodrigues if ((error = VOP_GETATTR(lvp, &lva, cred, td)) != 0) 734d00947d8SCraig Rodrigues return (error); 735d00947d8SCraig Rodrigues unionfs_create_uppervattr_core(ump, &lva, uvap, td); 736d00947d8SCraig Rodrigues 737d00947d8SCraig Rodrigues if (unp->un_path == NULL) 738d00947d8SCraig Rodrigues panic("unionfs: un_path is null"); 739d00947d8SCraig Rodrigues 740d00947d8SCraig Rodrigues cn.cn_namelen = strlen(unp->un_path); 741d00947d8SCraig Rodrigues cn.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 742d00947d8SCraig Rodrigues bcopy(unp->un_path, cn.cn_pnbuf, cn.cn_namelen + 1); 743d00947d8SCraig Rodrigues cn.cn_nameiop = CREATE; 744d00947d8SCraig Rodrigues cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN); 745d00947d8SCraig Rodrigues cn.cn_lkflags = LK_EXCLUSIVE; 746d00947d8SCraig Rodrigues cn.cn_thread = td; 747d00947d8SCraig Rodrigues cn.cn_cred = cred; 748d00947d8SCraig Rodrigues cn.cn_nameptr = cn.cn_pnbuf; 749d00947d8SCraig Rodrigues cn.cn_consume = 0; 750d00947d8SCraig Rodrigues 751d00947d8SCraig Rodrigues vref(udvp); 752d00947d8SCraig Rodrigues if ((error = relookup(udvp, &vp, &cn)) != 0) 753d00947d8SCraig Rodrigues goto unionfs_vn_create_on_upper_free_out2; 754d00947d8SCraig Rodrigues vrele(udvp); 755d00947d8SCraig Rodrigues 756d00947d8SCraig Rodrigues if (vp != NULLVP) { 757d00947d8SCraig Rodrigues if (vp == udvp) 758d00947d8SCraig Rodrigues vrele(vp); 759d00947d8SCraig Rodrigues else 760d00947d8SCraig Rodrigues vput(vp); 761d00947d8SCraig Rodrigues error = EEXIST; 762d00947d8SCraig Rodrigues goto unionfs_vn_create_on_upper_free_out1; 763d00947d8SCraig Rodrigues } 764d00947d8SCraig Rodrigues 765d00947d8SCraig Rodrigues if ((error = VOP_LEASE(udvp, td, cred, LEASE_WRITE)) != 0) 766d00947d8SCraig Rodrigues goto unionfs_vn_create_on_upper_free_out1; 767d00947d8SCraig Rodrigues 768d00947d8SCraig Rodrigues if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0) 769d00947d8SCraig Rodrigues goto unionfs_vn_create_on_upper_free_out1; 770d00947d8SCraig Rodrigues 7719e223287SKonstantin Belousov if ((error = VOP_OPEN(vp, fmode, cred, td, NULL)) != 0) { 772d00947d8SCraig Rodrigues vput(vp); 773d00947d8SCraig Rodrigues goto unionfs_vn_create_on_upper_free_out1; 774d00947d8SCraig Rodrigues } 775d00947d8SCraig Rodrigues vp->v_writecount++; 776d00947d8SCraig Rodrigues *vpp = vp; 777d00947d8SCraig Rodrigues 778d00947d8SCraig Rodrigues unionfs_vn_create_on_upper_free_out1: 779d00947d8SCraig Rodrigues VOP_UNLOCK(udvp, 0, td); 780d00947d8SCraig Rodrigues 781d00947d8SCraig Rodrigues unionfs_vn_create_on_upper_free_out2: 782d00947d8SCraig Rodrigues if (cn.cn_flags & HASBUF) { 783d00947d8SCraig Rodrigues uma_zfree(namei_zone, cn.cn_pnbuf); 784d00947d8SCraig Rodrigues cn.cn_flags &= ~HASBUF; 785d00947d8SCraig Rodrigues } 786d00947d8SCraig Rodrigues 787d00947d8SCraig Rodrigues return (error); 788d00947d8SCraig Rodrigues } 789d00947d8SCraig Rodrigues 790d00947d8SCraig Rodrigues /* 791d00947d8SCraig Rodrigues * Copy from lvp to uvp. 792d00947d8SCraig Rodrigues * 793d00947d8SCraig Rodrigues * lvp and uvp should be locked and opened on entry and will be locked and 794d00947d8SCraig Rodrigues * opened on return. 795d00947d8SCraig Rodrigues */ 796d00947d8SCraig Rodrigues static int 797d00947d8SCraig Rodrigues unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp, 798d00947d8SCraig Rodrigues struct ucred *cred, struct thread *td) 799d00947d8SCraig Rodrigues { 800d00947d8SCraig Rodrigues int error; 801d00947d8SCraig Rodrigues off_t offset; 802d00947d8SCraig Rodrigues int count; 803d00947d8SCraig Rodrigues int bufoffset; 804df8bae1dSRodney W. Grimes char *buf; 805df8bae1dSRodney W. Grimes struct uio uio; 806df8bae1dSRodney W. Grimes struct iovec iov; 807df8bae1dSRodney W. Grimes 808d00947d8SCraig Rodrigues error = 0; 809d00947d8SCraig Rodrigues memset(&uio, 0, sizeof(uio)); 8102a31267eSMatthew Dillon 811b40ce416SJulian Elischer uio.uio_td = td; 812df8bae1dSRodney W. Grimes uio.uio_segflg = UIO_SYSSPACE; 813df8bae1dSRodney W. Grimes uio.uio_offset = 0; 814df8bae1dSRodney W. Grimes 815d00947d8SCraig Rodrigues if ((error = VOP_LEASE(lvp, td, cred, LEASE_READ)) != 0) 816d00947d8SCraig Rodrigues return (error); 817d00947d8SCraig Rodrigues if ((error = VOP_LEASE(uvp, td, cred, LEASE_WRITE)) != 0) 818d00947d8SCraig Rodrigues return (error); 819a163d034SWarner Losh buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); 820df8bae1dSRodney W. Grimes 821d00947d8SCraig Rodrigues while (error == 0) { 822d00947d8SCraig Rodrigues offset = uio.uio_offset; 823df8bae1dSRodney W. Grimes 824df8bae1dSRodney W. Grimes uio.uio_iov = &iov; 825df8bae1dSRodney W. Grimes uio.uio_iovcnt = 1; 826df8bae1dSRodney W. Grimes iov.iov_base = buf; 827df8bae1dSRodney W. Grimes iov.iov_len = MAXBSIZE; 828df8bae1dSRodney W. Grimes uio.uio_resid = iov.iov_len; 829df8bae1dSRodney W. Grimes uio.uio_rw = UIO_READ; 830df8bae1dSRodney W. Grimes 831d00947d8SCraig Rodrigues if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0) 8322a31267eSMatthew Dillon break; 8332a31267eSMatthew Dillon if ((count = MAXBSIZE - uio.uio_resid) == 0) 8342a31267eSMatthew Dillon break; 8352a31267eSMatthew Dillon 836d00947d8SCraig Rodrigues bufoffset = 0; 8372a31267eSMatthew Dillon while (bufoffset < count) { 838df8bae1dSRodney W. Grimes uio.uio_iov = &iov; 839df8bae1dSRodney W. Grimes uio.uio_iovcnt = 1; 8402a31267eSMatthew Dillon iov.iov_base = buf + bufoffset; 8412a31267eSMatthew Dillon iov.iov_len = count - bufoffset; 8422a31267eSMatthew Dillon uio.uio_offset = offset + bufoffset; 843df8bae1dSRodney W. Grimes uio.uio_resid = iov.iov_len; 844d00947d8SCraig Rodrigues uio.uio_rw = UIO_WRITE; 845df8bae1dSRodney W. Grimes 846d00947d8SCraig Rodrigues if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0) 847df8bae1dSRodney W. Grimes break; 848d00947d8SCraig Rodrigues 8492a31267eSMatthew Dillon bufoffset += (count - bufoffset) - uio.uio_resid; 850df8bae1dSRodney W. Grimes } 851d00947d8SCraig Rodrigues 8522a31267eSMatthew Dillon uio.uio_offset = offset + bufoffset; 853d00947d8SCraig Rodrigues } 854df8bae1dSRodney W. Grimes 855df8bae1dSRodney W. Grimes free(buf, M_TEMP); 856d00947d8SCraig Rodrigues 857df8bae1dSRodney W. Grimes return (error); 858df8bae1dSRodney W. Grimes } 859df8bae1dSRodney W. Grimes 860df8bae1dSRodney W. Grimes /* 861d00947d8SCraig Rodrigues * Copy file from lower to upper. 8622a31267eSMatthew Dillon * 863d00947d8SCraig Rodrigues * If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to 864d00947d8SCraig Rodrigues * docopy. 865d00947d8SCraig Rodrigues * 866d00947d8SCraig Rodrigues * If no error returned, unp will be updated. 867996c772fSJohn Dyson */ 868996c772fSJohn Dyson int 869d00947d8SCraig Rodrigues unionfs_copyfile(struct unionfs_node *unp, int docopy, struct ucred *cred, 870d00947d8SCraig Rodrigues struct thread *td) 871996c772fSJohn Dyson { 872996c772fSJohn Dyson int error; 873f2a2857bSKirk McKusick struct mount *mp; 874d00947d8SCraig Rodrigues struct vnode *udvp; 875d00947d8SCraig Rodrigues struct vnode *lvp; 876d00947d8SCraig Rodrigues struct vnode *uvp; 877d00947d8SCraig Rodrigues struct vattr uva; 878996c772fSJohn Dyson 879d00947d8SCraig Rodrigues lvp = unp->un_lowervp; 880d00947d8SCraig Rodrigues uvp = NULLVP; 881d00947d8SCraig Rodrigues 882d00947d8SCraig Rodrigues if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY)) 883d00947d8SCraig Rodrigues return (EROFS); 884d00947d8SCraig Rodrigues if (unp->un_dvp == NULLVP) 885d00947d8SCraig Rodrigues return (EINVAL); 886d00947d8SCraig Rodrigues if (unp->un_uppervp != NULLVP) 887d00947d8SCraig Rodrigues return (EEXIST); 888d00947d8SCraig Rodrigues udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp; 889d00947d8SCraig Rodrigues if (udvp == NULLVP) 890d00947d8SCraig Rodrigues return (EROFS); 891d00947d8SCraig Rodrigues if ((udvp->v_mount->mnt_flag & MNT_RDONLY)) 892d00947d8SCraig Rodrigues return (EROFS); 893d00947d8SCraig Rodrigues 894d00947d8SCraig Rodrigues error = VOP_ACCESS(lvp, VREAD, cred, td); 895d00947d8SCraig Rodrigues if (error != 0) 8965842d4e5SKATO Takenori return (error); 8975842d4e5SKATO Takenori 898d00947d8SCraig Rodrigues if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)) != 0) 899996c772fSJohn Dyson return (error); 900d00947d8SCraig Rodrigues error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva, td); 901d00947d8SCraig Rodrigues if (error != 0) { 902f2a2857bSKirk McKusick vn_finished_write(mp); 903f2a2857bSKirk McKusick return (error); 904f2a2857bSKirk McKusick } 905996c772fSJohn Dyson 906d00947d8SCraig Rodrigues if (docopy != 0) { 9079e223287SKonstantin Belousov error = VOP_OPEN(lvp, FREAD, cred, td, NULL); 908996c772fSJohn Dyson if (error == 0) { 909d00947d8SCraig Rodrigues error = unionfs_copyfile_core(lvp, uvp, cred, td); 910d00947d8SCraig Rodrigues VOP_CLOSE(lvp, FREAD, cred, td); 911996c772fSJohn Dyson } 912d00947d8SCraig Rodrigues } 913d00947d8SCraig Rodrigues VOP_CLOSE(uvp, FWRITE, cred, td); 914d00947d8SCraig Rodrigues uvp->v_writecount--; 915996c772fSJohn Dyson 916f2a2857bSKirk McKusick vn_finished_write(mp); 917d00947d8SCraig Rodrigues 918996c772fSJohn Dyson if (error == 0) { 919d00947d8SCraig Rodrigues /* Reset the attributes. Ignore errors. */ 920d00947d8SCraig Rodrigues uva.va_type = VNON; 921d00947d8SCraig Rodrigues VOP_SETATTR(uvp, &uva, cred, td); 922996c772fSJohn Dyson } 923996c772fSJohn Dyson 924d00947d8SCraig Rodrigues unionfs_node_update(unp, uvp, td); 925996c772fSJohn Dyson 9262a31267eSMatthew Dillon return (error); 927b422956cSPoul-Henning Kamp } 928996c772fSJohn Dyson 9292a31267eSMatthew Dillon /* 930d00947d8SCraig Rodrigues * It checks whether vp can rmdir. (check empty) 9312a31267eSMatthew Dillon * 932d00947d8SCraig Rodrigues * vp is unionfs vnode. 933d00947d8SCraig Rodrigues * vp should be locked. 934df8bae1dSRodney W. Grimes */ 935df8bae1dSRodney W. Grimes int 936d00947d8SCraig Rodrigues unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td) 937df8bae1dSRodney W. Grimes { 938df8bae1dSRodney W. Grimes int error; 939d00947d8SCraig Rodrigues int eofflag; 940d00947d8SCraig Rodrigues int lookuperr; 941d00947d8SCraig Rodrigues struct vnode *uvp; 942d00947d8SCraig Rodrigues struct vnode *lvp; 943d00947d8SCraig Rodrigues struct vnode *tvp; 944df8bae1dSRodney W. Grimes struct vattr va; 945df8bae1dSRodney W. Grimes struct componentname cn; 946df8bae1dSRodney W. Grimes /* 947d00947d8SCraig Rodrigues * The size of buf needs to be larger than DIRBLKSIZ. 948df8bae1dSRodney W. Grimes */ 949d00947d8SCraig Rodrigues char buf[256 * 6]; 950d00947d8SCraig Rodrigues struct dirent *dp; 951d00947d8SCraig Rodrigues struct dirent *edp; 952d00947d8SCraig Rodrigues struct uio uio; 953d00947d8SCraig Rodrigues struct iovec iov; 954df8bae1dSRodney W. Grimes 955d00947d8SCraig Rodrigues ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir"); 956df8bae1dSRodney W. Grimes 957d00947d8SCraig Rodrigues eofflag = 0; 958d00947d8SCraig Rodrigues uvp = UNIONFSVPTOUPPERVP(vp); 959d00947d8SCraig Rodrigues lvp = UNIONFSVPTOLOWERVP(vp); 960df8bae1dSRodney W. Grimes 961d00947d8SCraig Rodrigues /* check opaque */ 962d00947d8SCraig Rodrigues if ((error = VOP_GETATTR(uvp, &va, cred, td)) != 0) 963df8bae1dSRodney W. Grimes return (error); 964d00947d8SCraig Rodrigues if (va.va_flags & OPAQUE) 965d00947d8SCraig Rodrigues return (0); 966df8bae1dSRodney W. Grimes 967d00947d8SCraig Rodrigues /* open vnode */ 9683282e2c4SDaichi GOTO #ifdef MAC 96930d239bcSRobert Watson if ((error = mac_vnode_check_open(cred, vp, VEXEC|VREAD)) != 0) 9703282e2c4SDaichi GOTO return (error); 9713282e2c4SDaichi GOTO #endif 9723282e2c4SDaichi GOTO if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0) 9733282e2c4SDaichi GOTO return (error); 9749e223287SKonstantin Belousov if ((error = VOP_OPEN(vp, FREAD, cred, td, NULL)) != 0) 975996c772fSJohn Dyson return (error); 976996c772fSJohn Dyson 977d00947d8SCraig Rodrigues uio.uio_rw = UIO_READ; 978d00947d8SCraig Rodrigues uio.uio_segflg = UIO_SYSSPACE; 979d00947d8SCraig Rodrigues uio.uio_td = td; 980d00947d8SCraig Rodrigues uio.uio_offset = 0; 981996c772fSJohn Dyson 982d00947d8SCraig Rodrigues #ifdef MAC 98330d239bcSRobert Watson error = mac_vnode_check_readdir(td->td_ucred, lvp); 984d00947d8SCraig Rodrigues #endif 985d00947d8SCraig Rodrigues while (!error && !eofflag) { 986d00947d8SCraig Rodrigues iov.iov_base = buf; 987d00947d8SCraig Rodrigues iov.iov_len = sizeof(buf); 988d00947d8SCraig Rodrigues uio.uio_iov = &iov; 989d00947d8SCraig Rodrigues uio.uio_iovcnt = 1; 990d00947d8SCraig Rodrigues uio.uio_resid = iov.iov_len; 991996c772fSJohn Dyson 992d00947d8SCraig Rodrigues error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL); 993d00947d8SCraig Rodrigues if (error) 994d00947d8SCraig Rodrigues break; 995996c772fSJohn Dyson 996d00947d8SCraig Rodrigues edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid]; 997d00947d8SCraig Rodrigues for (dp = (struct dirent*)buf; !error && dp < edp; 998d00947d8SCraig Rodrigues dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) { 999d00947d8SCraig Rodrigues if (dp->d_type == DT_WHT || 1000d00947d8SCraig Rodrigues (dp->d_namlen == 1 && dp->d_name[0] == '.') || 1001d00947d8SCraig Rodrigues (dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2))) 1002d00947d8SCraig Rodrigues continue; 1003df8bae1dSRodney W. Grimes 1004d00947d8SCraig Rodrigues cn.cn_namelen = dp->d_namlen; 1005d00947d8SCraig Rodrigues cn.cn_pnbuf = NULL; 1006d00947d8SCraig Rodrigues cn.cn_nameptr = dp->d_name; 1007d00947d8SCraig Rodrigues cn.cn_nameiop = LOOKUP; 1008d00947d8SCraig Rodrigues cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN); 1009d00947d8SCraig Rodrigues cn.cn_lkflags = LK_EXCLUSIVE; 1010b40ce416SJulian Elischer cn.cn_thread = td; 1011d00947d8SCraig Rodrigues cn.cn_cred = cred; 1012df8bae1dSRodney W. Grimes cn.cn_consume = 0; 1013df8bae1dSRodney W. Grimes 10142a31267eSMatthew Dillon /* 1015d00947d8SCraig Rodrigues * check entry in lower. 1016d00947d8SCraig Rodrigues * Sometimes, readdir function returns 1017d00947d8SCraig Rodrigues * wrong entry. 10182a31267eSMatthew Dillon */ 1019d00947d8SCraig Rodrigues lookuperr = VOP_LOOKUP(lvp, &tvp, &cn); 1020df8bae1dSRodney W. Grimes 1021d00947d8SCraig Rodrigues if (!lookuperr) 1022d00947d8SCraig Rodrigues vput(tvp); 10232a31267eSMatthew Dillon else 1024d00947d8SCraig Rodrigues continue; /* skip entry */ 1025df8bae1dSRodney W. Grimes 1026df8bae1dSRodney W. Grimes /* 1027d00947d8SCraig Rodrigues * check entry 1028d00947d8SCraig Rodrigues * If it has no exist/whiteout entry in upper, 1029d00947d8SCraig Rodrigues * directory is not empty. 1030df8bae1dSRodney W. Grimes */ 1031d00947d8SCraig Rodrigues cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN); 1032d00947d8SCraig Rodrigues lookuperr = VOP_LOOKUP(uvp, &tvp, &cn); 1033df8bae1dSRodney W. Grimes 1034d00947d8SCraig Rodrigues if (!lookuperr) 1035d00947d8SCraig Rodrigues vput(tvp); 1036df8bae1dSRodney W. Grimes 1037d00947d8SCraig Rodrigues /* ignore exist or whiteout entry */ 1038d00947d8SCraig Rodrigues if (!lookuperr || 1039d00947d8SCraig Rodrigues (lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT))) 104001634480SBrian Feldman continue; 1041d00947d8SCraig Rodrigues 1042d00947d8SCraig Rodrigues error = ENOTEMPTY; 1043df8bae1dSRodney W. Grimes } 1044996c772fSJohn Dyson } 1045996c772fSJohn Dyson 1046d00947d8SCraig Rodrigues /* close vnode */ 1047d00947d8SCraig Rodrigues VOP_CLOSE(vp, FREAD, cred, td); 1048d00947d8SCraig Rodrigues 1049d00947d8SCraig Rodrigues return (error); 1050d00947d8SCraig Rodrigues } 1051d00947d8SCraig Rodrigues 1052d00947d8SCraig Rodrigues #ifdef DIAGNOSTIC 1053d00947d8SCraig Rodrigues 1054d00947d8SCraig Rodrigues struct vnode * 1055d00947d8SCraig Rodrigues unionfs_checkuppervp(struct vnode *vp, char *fil, int lno) 1056996c772fSJohn Dyson { 1057d00947d8SCraig Rodrigues struct unionfs_node *unp; 1058996c772fSJohn Dyson 1059d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1060996c772fSJohn Dyson 1061d00947d8SCraig Rodrigues #ifdef notyet 1062d00947d8SCraig Rodrigues if (vp->v_op != unionfs_vnodeop_p) { 1063d00947d8SCraig Rodrigues printf("unionfs_checkuppervp: on non-unionfs-node.\n"); 1064d00947d8SCraig Rodrigues #ifdef KDB 10653de213ccSRobert Watson kdb_enter(KDB_WHY_UNIONFS, 10663de213ccSRobert Watson "unionfs_checkuppervp: on non-unionfs-node.\n"); 1067d00947d8SCraig Rodrigues #endif 1068d00947d8SCraig Rodrigues panic("unionfs_checkuppervp"); 1069d00947d8SCraig Rodrigues }; 1070d00947d8SCraig Rodrigues #endif 1071d00947d8SCraig Rodrigues return (unp->un_uppervp); 1072d8c6e674SDavid Schultz } 1073996c772fSJohn Dyson 1074996c772fSJohn Dyson struct vnode * 1075d00947d8SCraig Rodrigues unionfs_checklowervp(struct vnode *vp, char *fil, int lno) 1076996c772fSJohn Dyson { 1077d00947d8SCraig Rodrigues struct unionfs_node *unp; 1078996c772fSJohn Dyson 1079d00947d8SCraig Rodrigues unp = VTOUNIONFS(vp); 1080996c772fSJohn Dyson 1081d00947d8SCraig Rodrigues #ifdef notyet 1082d00947d8SCraig Rodrigues if (vp->v_op != unionfs_vnodeop_p) { 1083d00947d8SCraig Rodrigues printf("unionfs_checklowervp: on non-unionfs-node.\n"); 1084d00947d8SCraig Rodrigues #ifdef KDB 10853de213ccSRobert Watson kdb_enter(KDB_WHY_UNIONFS, 10863de213ccSRobert Watson "unionfs_checklowervp: on non-unionfs-node.\n"); 1087d00947d8SCraig Rodrigues #endif 1088d00947d8SCraig Rodrigues panic("unionfs_checklowervp"); 10898c14bf40SPeter Wemm }; 1090d00947d8SCraig Rodrigues #endif 1091d00947d8SCraig Rodrigues return (unp->un_lowervp); 1092d00947d8SCraig Rodrigues } 1093d00947d8SCraig Rodrigues #endif 1094