1df8bae1dSRodney W. Grimes /* 2996c772fSJohn Dyson * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry. 3996c772fSJohn Dyson * Copyright (c) 1992, 1993, 1994, 1995 4996c772fSJohn Dyson * The Regents of the University of California. All rights reserved. 5df8bae1dSRodney W. Grimes * 6df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 7df8bae1dSRodney W. Grimes * Jan-Simon Pendry. 8df8bae1dSRodney W. Grimes * 9df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 10df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 11df8bae1dSRodney W. Grimes * are met: 12df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 14df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 16df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 17df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 18df8bae1dSRodney W. Grimes * must display the following acknowledgement: 19df8bae1dSRodney W. Grimes * This product includes software developed by the University of 20df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 21df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 22df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 23df8bae1dSRodney W. Grimes * without specific prior written permission. 24df8bae1dSRodney W. Grimes * 25df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35df8bae1dSRodney W. Grimes * SUCH DAMAGE. 36df8bae1dSRodney W. Grimes * 37996c772fSJohn Dyson * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 38f8fc96b5SKATO Takenori * $Id: union_vnops.c,v 1.34 1997/05/07 14:37:32 kato Exp $ 39df8bae1dSRodney W. Grimes */ 40df8bae1dSRodney W. Grimes 41df8bae1dSRodney W. Grimes #include <sys/param.h> 42df8bae1dSRodney W. Grimes #include <sys/systm.h> 43df8bae1dSRodney W. Grimes #include <sys/proc.h> 443ac4d1efSBruce Evans #include <sys/fcntl.h> 45df8bae1dSRodney W. Grimes #include <sys/time.h> 46996c772fSJohn Dyson #include <sys/stat.h> 47df8bae1dSRodney W. Grimes #include <sys/types.h> 489e67ea79SBruce Evans #include <sys/kernel.h> 49df8bae1dSRodney W. Grimes #include <sys/vnode.h> 50df8bae1dSRodney W. Grimes #include <sys/mount.h> 51df8bae1dSRodney W. Grimes #include <sys/namei.h> 52df8bae1dSRodney W. Grimes #include <sys/malloc.h> 53df8bae1dSRodney W. Grimes #include <sys/buf.h> 54df8bae1dSRodney W. Grimes #include <sys/queue.h> 55996c772fSJohn Dyson #include <sys/lock.h> 56df8bae1dSRodney W. Grimes #include <miscfs/union/union.h> 57df8bae1dSRodney W. Grimes 58996c772fSJohn Dyson #define FIXUP(un, p) { \ 59996c772fSJohn Dyson if (((un)->un_flags & UN_ULOCK) == 0) { \ 60996c772fSJohn Dyson union_fixup(un, p); \ 61df8bae1dSRodney W. Grimes } \ 62df8bae1dSRodney W. Grimes } 63df8bae1dSRodney W. Grimes 64a9320ff3SKATO Takenori #define SETKLOCK(un) (un)->un_flags |= UN_KLOCK 65a9320ff3SKATO Takenori #define CLEARKLOCK(un) (un)->un_flags &= ~UN_KLOCK 66a9320ff3SKATO Takenori 67c9bf0111SKATO Takenori static int union_abortop __P((struct vop_abortop_args *ap)); 68c9bf0111SKATO Takenori static int union_access __P((struct vop_access_args *ap)); 69c9bf0111SKATO Takenori static int union_advlock __P((struct vop_advlock_args *ap)); 70c9bf0111SKATO Takenori static int union_bmap __P((struct vop_bmap_args *ap)); 71c9bf0111SKATO Takenori static int union_close __P((struct vop_close_args *ap)); 72c9bf0111SKATO Takenori static int union_create __P((struct vop_create_args *ap)); 73996c772fSJohn Dyson static void union_fixup __P((struct union_node *un, struct proc *p)); 74c9bf0111SKATO Takenori static int union_fsync __P((struct vop_fsync_args *ap)); 75c9bf0111SKATO Takenori static int union_getattr __P((struct vop_getattr_args *ap)); 76c9bf0111SKATO Takenori static int union_inactive __P((struct vop_inactive_args *ap)); 77c9bf0111SKATO Takenori static int union_ioctl __P((struct vop_ioctl_args *ap)); 78c9bf0111SKATO Takenori static int union_islocked __P((struct vop_islocked_args *ap)); 79c9bf0111SKATO Takenori static int union_lease __P((struct vop_lease_args *ap)); 80c9bf0111SKATO Takenori static int union_link __P((struct vop_link_args *ap)); 81c9bf0111SKATO Takenori static int union_lock __P((struct vop_lock_args *ap)); 82c9bf0111SKATO Takenori static int union_lookup __P((struct vop_lookup_args *ap)); 83996c772fSJohn Dyson static int union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp, 849b5e8b3aSBruce Evans struct vnode **vpp, 859b5e8b3aSBruce Evans struct componentname *cnp)); 86c9bf0111SKATO Takenori static int union_mkdir __P((struct vop_mkdir_args *ap)); 87c9bf0111SKATO Takenori static int union_mknod __P((struct vop_mknod_args *ap)); 88c9bf0111SKATO Takenori static int union_mmap __P((struct vop_mmap_args *ap)); 89c9bf0111SKATO Takenori static int union_open __P((struct vop_open_args *ap)); 90c9bf0111SKATO Takenori static int union_pathconf __P((struct vop_pathconf_args *ap)); 91c9bf0111SKATO Takenori static int union_print __P((struct vop_print_args *ap)); 92c9bf0111SKATO Takenori static int union_read __P((struct vop_read_args *ap)); 93c9bf0111SKATO Takenori static int union_readdir __P((struct vop_readdir_args *ap)); 94c9bf0111SKATO Takenori static int union_readlink __P((struct vop_readlink_args *ap)); 95c9bf0111SKATO Takenori static int union_reclaim __P((struct vop_reclaim_args *ap)); 96c9bf0111SKATO Takenori static int union_remove __P((struct vop_remove_args *ap)); 97c9bf0111SKATO Takenori static int union_rename __P((struct vop_rename_args *ap)); 98c9bf0111SKATO Takenori static int union_revoke __P((struct vop_revoke_args *ap)); 99c9bf0111SKATO Takenori static int union_rmdir __P((struct vop_rmdir_args *ap)); 100c9bf0111SKATO Takenori static int union_seek __P((struct vop_seek_args *ap)); 101c9bf0111SKATO Takenori static int union_select __P((struct vop_select_args *ap)); 102c9bf0111SKATO Takenori static int union_setattr __P((struct vop_setattr_args *ap)); 103c9bf0111SKATO Takenori static int union_strategy __P((struct vop_strategy_args *ap)); 104c9bf0111SKATO Takenori static int union_symlink __P((struct vop_symlink_args *ap)); 105c9bf0111SKATO Takenori static int union_unlock __P((struct vop_unlock_args *ap)); 106c9bf0111SKATO Takenori static int union_whiteout __P((struct vop_whiteout_args *ap)); 107c9bf0111SKATO Takenori static int union_write __P((struct vop_read_args *ap)); 1089b5e8b3aSBruce Evans 109df8bae1dSRodney W. Grimes static void 110996c772fSJohn Dyson union_fixup(un, p) 111df8bae1dSRodney W. Grimes struct union_node *un; 112996c772fSJohn Dyson struct proc *p; 113df8bae1dSRodney W. Grimes { 114df8bae1dSRodney W. Grimes 115996c772fSJohn Dyson vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p); 116df8bae1dSRodney W. Grimes un->un_flags |= UN_ULOCK; 117df8bae1dSRodney W. Grimes } 118df8bae1dSRodney W. Grimes 119df8bae1dSRodney W. Grimes static int 120996c772fSJohn Dyson union_lookup1(udvp, dvpp, vpp, cnp) 121df8bae1dSRodney W. Grimes struct vnode *udvp; 122996c772fSJohn Dyson struct vnode **dvpp; 123df8bae1dSRodney W. Grimes struct vnode **vpp; 124df8bae1dSRodney W. Grimes struct componentname *cnp; 125df8bae1dSRodney W. Grimes { 126df8bae1dSRodney W. Grimes int error; 127996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 128df8bae1dSRodney W. Grimes struct vnode *tdvp; 129996c772fSJohn Dyson struct vnode *dvp; 130df8bae1dSRodney W. Grimes struct mount *mp; 131df8bae1dSRodney W. Grimes 132996c772fSJohn Dyson dvp = *dvpp; 133996c772fSJohn Dyson 134df8bae1dSRodney W. Grimes /* 135df8bae1dSRodney W. Grimes * If stepping up the directory tree, check for going 136df8bae1dSRodney W. Grimes * back across the mount point, in which case do what 137df8bae1dSRodney W. Grimes * lookup would do by stepping back down the mount 138df8bae1dSRodney W. Grimes * hierarchy. 139df8bae1dSRodney W. Grimes */ 140df8bae1dSRodney W. Grimes if (cnp->cn_flags & ISDOTDOT) { 141996c772fSJohn Dyson while ((dvp != udvp) && (dvp->v_flag & VROOT)) { 142df8bae1dSRodney W. Grimes /* 143df8bae1dSRodney W. Grimes * Don't do the NOCROSSMOUNT check 144df8bae1dSRodney W. Grimes * at this level. By definition, 145df8bae1dSRodney W. Grimes * union fs deals with namespaces, not 146df8bae1dSRodney W. Grimes * filesystems. 147df8bae1dSRodney W. Grimes */ 148df8bae1dSRodney W. Grimes tdvp = dvp; 149996c772fSJohn Dyson *dvpp = dvp = dvp->v_mount->mnt_vnodecovered; 150df8bae1dSRodney W. Grimes vput(tdvp); 151df8bae1dSRodney W. Grimes VREF(dvp); 152996c772fSJohn Dyson vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 153df8bae1dSRodney W. Grimes } 154df8bae1dSRodney W. Grimes } 155df8bae1dSRodney W. Grimes 156df8bae1dSRodney W. Grimes error = VOP_LOOKUP(dvp, &tdvp, cnp); 157df8bae1dSRodney W. Grimes if (error) 158df8bae1dSRodney W. Grimes return (error); 159df8bae1dSRodney W. Grimes 160df8bae1dSRodney W. Grimes /* 161df8bae1dSRodney W. Grimes * The parent directory will have been unlocked, unless lookup 162df8bae1dSRodney W. Grimes * found the last component. In which case, re-lock the node 163df8bae1dSRodney W. Grimes * here to allow it to be unlocked again (phew) in union_lookup. 164df8bae1dSRodney W. Grimes */ 165df8bae1dSRodney W. Grimes if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN)) 166996c772fSJohn Dyson vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 167df8bae1dSRodney W. Grimes 168df8bae1dSRodney W. Grimes dvp = tdvp; 169df8bae1dSRodney W. Grimes 170df8bae1dSRodney W. Grimes /* 171df8bae1dSRodney W. Grimes * Lastly check if the current node is a mount point in 172df8bae1dSRodney W. Grimes * which case walk up the mount hierarchy making sure not to 173df8bae1dSRodney W. Grimes * bump into the root of the mount tree (ie. dvp != udvp). 174df8bae1dSRodney W. Grimes */ 175df8bae1dSRodney W. Grimes while (dvp != udvp && (dvp->v_type == VDIR) && 176df8bae1dSRodney W. Grimes (mp = dvp->v_mountedhere)) { 177df8bae1dSRodney W. Grimes 178996c772fSJohn Dyson if (vfs_busy(mp, 0, 0, p)) 179df8bae1dSRodney W. Grimes continue; 180df8bae1dSRodney W. Grimes 1813a773ad0SPoul-Henning Kamp error = VFS_ROOT(mp, &tdvp); 182996c772fSJohn Dyson vfs_unbusy(mp, p); 1833a773ad0SPoul-Henning Kamp if (error) { 184df8bae1dSRodney W. Grimes vput(dvp); 185df8bae1dSRodney W. Grimes return (error); 186df8bae1dSRodney W. Grimes } 187df8bae1dSRodney W. Grimes 188df8bae1dSRodney W. Grimes vput(dvp); 189df8bae1dSRodney W. Grimes dvp = tdvp; 190df8bae1dSRodney W. Grimes } 191df8bae1dSRodney W. Grimes 192df8bae1dSRodney W. Grimes *vpp = dvp; 193df8bae1dSRodney W. Grimes return (0); 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes 196c9bf0111SKATO Takenori static int 197df8bae1dSRodney W. Grimes union_lookup(ap) 198df8bae1dSRodney W. Grimes struct vop_lookup_args /* { 199df8bae1dSRodney W. Grimes struct vnodeop_desc *a_desc; 200df8bae1dSRodney W. Grimes struct vnode *a_dvp; 201df8bae1dSRodney W. Grimes struct vnode **a_vpp; 202df8bae1dSRodney W. Grimes struct componentname *a_cnp; 203df8bae1dSRodney W. Grimes } */ *ap; 204df8bae1dSRodney W. Grimes { 205df8bae1dSRodney W. Grimes int error; 206df8bae1dSRodney W. Grimes int uerror, lerror; 207df8bae1dSRodney W. Grimes struct vnode *uppervp, *lowervp; 208df8bae1dSRodney W. Grimes struct vnode *upperdvp, *lowerdvp; 209df8bae1dSRodney W. Grimes struct vnode *dvp = ap->a_dvp; 210df8bae1dSRodney W. Grimes struct union_node *dun = VTOUNION(dvp); 211df8bae1dSRodney W. Grimes struct componentname *cnp = ap->a_cnp; 212996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 213df8bae1dSRodney W. Grimes int lockparent = cnp->cn_flags & LOCKPARENT; 214df8bae1dSRodney W. Grimes struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount); 215996c772fSJohn Dyson struct ucred *saved_cred; 216996c772fSJohn Dyson int iswhiteout; 217996c772fSJohn Dyson struct vattr va; 218996c772fSJohn Dyson 219996c772fSJohn Dyson #ifdef notyet 220996c772fSJohn Dyson if (cnp->cn_namelen == 3 && 221996c772fSJohn Dyson cnp->cn_nameptr[2] == '.' && 222996c772fSJohn Dyson cnp->cn_nameptr[1] == '.' && 223996c772fSJohn Dyson cnp->cn_nameptr[0] == '.') { 224996c772fSJohn Dyson dvp = *ap->a_vpp = LOWERVP(ap->a_dvp); 225996c772fSJohn Dyson if (dvp == NULLVP) 226996c772fSJohn Dyson return (ENOENT); 227996c772fSJohn Dyson VREF(dvp); 228996c772fSJohn Dyson vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 229996c772fSJohn Dyson if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 230996c772fSJohn Dyson VOP_UNLOCK(ap->a_dvp, 0, p); 231996c772fSJohn Dyson return (0); 232996c772fSJohn Dyson } 233996c772fSJohn Dyson #endif 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes cnp->cn_flags |= LOCKPARENT; 236df8bae1dSRodney W. Grimes 237df8bae1dSRodney W. Grimes upperdvp = dun->un_uppervp; 238df8bae1dSRodney W. Grimes lowerdvp = dun->un_lowervp; 239df8bae1dSRodney W. Grimes uppervp = NULLVP; 240df8bae1dSRodney W. Grimes lowervp = NULLVP; 241996c772fSJohn Dyson iswhiteout = 0; 242df8bae1dSRodney W. Grimes 243df8bae1dSRodney W. Grimes /* 244df8bae1dSRodney W. Grimes * do the lookup in the upper level. 245df8bae1dSRodney W. Grimes * if that level comsumes additional pathnames, 246df8bae1dSRodney W. Grimes * then assume that something special is going 247df8bae1dSRodney W. Grimes * on and just return that vnode. 248df8bae1dSRodney W. Grimes */ 249996c772fSJohn Dyson if (upperdvp != NULLVP) { 250996c772fSJohn Dyson FIXUP(dun, p); 251ee582cdfSKATO Takenori /* 252ee582cdfSKATO Takenori * If we're doing `..' in the underlying filesystem, 253ee582cdfSKATO Takenori * we must drop our lock on the union node before 254ee582cdfSKATO Takenori * going up the tree in the lower file system--if we block 255ee582cdfSKATO Takenori * on the lowervp lock, and that's held by someone else 256ee582cdfSKATO Takenori * coming down the tree and who's waiting for our lock, 257ee582cdfSKATO Takenori * we would be hosed. 258ee582cdfSKATO Takenori */ 259ee582cdfSKATO Takenori if (cnp->cn_flags & ISDOTDOT) { 260ee582cdfSKATO Takenori /* retain lock on underlying VP: */ 261a9320ff3SKATO Takenori SETKLOCK(dun); 262ee582cdfSKATO Takenori VOP_UNLOCK(dvp, 0, p); 263a9320ff3SKATO Takenori CLEARKLOCK(dun); 264ee582cdfSKATO Takenori } 265996c772fSJohn Dyson uerror = union_lookup1(um->um_uppervp, &upperdvp, 266df8bae1dSRodney W. Grimes &uppervp, cnp); 267ee582cdfSKATO Takenori if (cnp->cn_flags & ISDOTDOT) { 268ee582cdfSKATO Takenori if (dun->un_uppervp == upperdvp) { 269ee582cdfSKATO Takenori /* 270ee582cdfSKATO Takenori * We got the underlying bugger back locked... 271ee582cdfSKATO Takenori * now take back the union node lock. Since we 272ee582cdfSKATO Takenori * hold the uppervp lock, we can diddle union 273ee582cdfSKATO Takenori * locking flags at will. :) 274ee582cdfSKATO Takenori */ 275ee582cdfSKATO Takenori dun->un_flags |= UN_ULOCK; 276ee582cdfSKATO Takenori } 277ee582cdfSKATO Takenori /* 278ee582cdfSKATO Takenori * If upperdvp got swapped out, it means we did 279ee582cdfSKATO Takenori * some mount point magic, and we do not have 280ee582cdfSKATO Takenori * dun->un_uppervp locked currently--so we get it 281ee582cdfSKATO Takenori * locked here (don't set the UN_ULOCK flag). 282ee582cdfSKATO Takenori */ 283077f31beSKATO Takenori vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 284ee582cdfSKATO Takenori } 285ee582cdfSKATO Takenori 286df8bae1dSRodney W. Grimes /*if (uppervp == upperdvp) 287df8bae1dSRodney W. Grimes dun->un_flags |= UN_KLOCK;*/ 288df8bae1dSRodney W. Grimes 289f8fc96b5SKATO Takenori if (cnp->cn_consume != 0 || uerror == EACCES) { 290f8fc96b5SKATO Takenori if (uerror == EACCES) 291f8fc96b5SKATO Takenori uppervp = NULLVP; 292df8bae1dSRodney W. Grimes *ap->a_vpp = uppervp; 293df8bae1dSRodney W. Grimes if (!lockparent) 294df8bae1dSRodney W. Grimes cnp->cn_flags &= ~LOCKPARENT; 295df8bae1dSRodney W. Grimes return (uerror); 296df8bae1dSRodney W. Grimes } 297996c772fSJohn Dyson if (uerror == ENOENT || uerror == EJUSTRETURN) { 298996c772fSJohn Dyson if (cnp->cn_flags & ISWHITEOUT) { 299996c772fSJohn Dyson iswhiteout = 1; 300996c772fSJohn Dyson } else if (lowerdvp != NULLVP) { 301996c772fSJohn Dyson lerror = VOP_GETATTR(upperdvp, &va, 302996c772fSJohn Dyson cnp->cn_cred, cnp->cn_proc); 303996c772fSJohn Dyson if (lerror == 0 && (va.va_flags & OPAQUE)) 304996c772fSJohn Dyson iswhiteout = 1; 305996c772fSJohn Dyson } 306996c772fSJohn Dyson } 307df8bae1dSRodney W. Grimes } else { 308df8bae1dSRodney W. Grimes uerror = ENOENT; 309df8bae1dSRodney W. Grimes } 310df8bae1dSRodney W. Grimes 311df8bae1dSRodney W. Grimes /* 312df8bae1dSRodney W. Grimes * in a similar way to the upper layer, do the lookup 313df8bae1dSRodney W. Grimes * in the lower layer. this time, if there is some 314df8bae1dSRodney W. Grimes * component magic going on, then vput whatever we got 315df8bae1dSRodney W. Grimes * back from the upper layer and return the lower vnode 316df8bae1dSRodney W. Grimes * instead. 317df8bae1dSRodney W. Grimes */ 318996c772fSJohn Dyson if (lowerdvp != NULLVP && !iswhiteout) { 319df8bae1dSRodney W. Grimes int nameiop; 320df8bae1dSRodney W. Grimes 321996c772fSJohn Dyson vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p); 322df8bae1dSRodney W. Grimes 323df8bae1dSRodney W. Grimes /* 324df8bae1dSRodney W. Grimes * Only do a LOOKUP on the bottom node, since 325df8bae1dSRodney W. Grimes * we won't be making changes to it anyway. 326df8bae1dSRodney W. Grimes */ 327df8bae1dSRodney W. Grimes nameiop = cnp->cn_nameiop; 328df8bae1dSRodney W. Grimes cnp->cn_nameiop = LOOKUP; 329df8bae1dSRodney W. Grimes if (um->um_op == UNMNT_BELOW) { 330df8bae1dSRodney W. Grimes saved_cred = cnp->cn_cred; 331df8bae1dSRodney W. Grimes cnp->cn_cred = um->um_cred; 332df8bae1dSRodney W. Grimes } 333ee582cdfSKATO Takenori /* 334ee582cdfSKATO Takenori * We shouldn't have to worry about locking interactions 335ee582cdfSKATO Takenori * between the lower layer and our union layer (w.r.t. 336ee582cdfSKATO Takenori * `..' processing) because we don't futz with lowervp 337ee582cdfSKATO Takenori * locks in the union-node instantiation code path. 338ee582cdfSKATO Takenori */ 339996c772fSJohn Dyson lerror = union_lookup1(um->um_lowervp, &lowerdvp, 340df8bae1dSRodney W. Grimes &lowervp, cnp); 341df8bae1dSRodney W. Grimes if (um->um_op == UNMNT_BELOW) 342df8bae1dSRodney W. Grimes cnp->cn_cred = saved_cred; 343df8bae1dSRodney W. Grimes cnp->cn_nameiop = nameiop; 344df8bae1dSRodney W. Grimes 345df8bae1dSRodney W. Grimes if (lowervp != lowerdvp) 346996c772fSJohn Dyson VOP_UNLOCK(lowerdvp, 0, p); 347df8bae1dSRodney W. Grimes 348f8fc96b5SKATO Takenori if (cnp->cn_consume != 0 || lerror == EACCES) { 349f8fc96b5SKATO Takenori if (lerror == EACCES) 350f8fc96b5SKATO Takenori lowervp = NULLVP; 351996c772fSJohn Dyson if (uppervp != NULLVP) { 352df8bae1dSRodney W. Grimes if (uppervp == upperdvp) 353df8bae1dSRodney W. Grimes vrele(uppervp); 354df8bae1dSRodney W. Grimes else 355df8bae1dSRodney W. Grimes vput(uppervp); 356df8bae1dSRodney W. Grimes uppervp = NULLVP; 357df8bae1dSRodney W. Grimes } 358df8bae1dSRodney W. Grimes *ap->a_vpp = lowervp; 359df8bae1dSRodney W. Grimes if (!lockparent) 360df8bae1dSRodney W. Grimes cnp->cn_flags &= ~LOCKPARENT; 361df8bae1dSRodney W. Grimes return (lerror); 362df8bae1dSRodney W. Grimes } 363df8bae1dSRodney W. Grimes } else { 364df8bae1dSRodney W. Grimes lerror = ENOENT; 365996c772fSJohn Dyson if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) { 366996c772fSJohn Dyson lowervp = LOWERVP(dun->un_pvp); 367996c772fSJohn Dyson if (lowervp != NULLVP) { 368996c772fSJohn Dyson VREF(lowervp); 369996c772fSJohn Dyson vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p); 370996c772fSJohn Dyson lerror = 0; 371996c772fSJohn Dyson } 372996c772fSJohn Dyson } 373df8bae1dSRodney W. Grimes } 374df8bae1dSRodney W. Grimes 375df8bae1dSRodney W. Grimes if (!lockparent) 376df8bae1dSRodney W. Grimes cnp->cn_flags &= ~LOCKPARENT; 377df8bae1dSRodney W. Grimes 378df8bae1dSRodney W. Grimes /* 379df8bae1dSRodney W. Grimes * at this point, we have uerror and lerror indicating 380df8bae1dSRodney W. Grimes * possible errors with the lookups in the upper and lower 381df8bae1dSRodney W. Grimes * layers. additionally, uppervp and lowervp are (locked) 382df8bae1dSRodney W. Grimes * references to existing vnodes in the upper and lower layers. 383df8bae1dSRodney W. Grimes * 384df8bae1dSRodney W. Grimes * there are now three cases to consider. 385df8bae1dSRodney W. Grimes * 1. if both layers returned an error, then return whatever 386df8bae1dSRodney W. Grimes * error the upper layer generated. 387df8bae1dSRodney W. Grimes * 388df8bae1dSRodney W. Grimes * 2. if the top layer failed and the bottom layer succeeded 389df8bae1dSRodney W. Grimes * then two subcases occur. 390df8bae1dSRodney W. Grimes * a. the bottom vnode is not a directory, in which 391df8bae1dSRodney W. Grimes * case just return a new union vnode referencing 392df8bae1dSRodney W. Grimes * an empty top layer and the existing bottom layer. 393df8bae1dSRodney W. Grimes * b. the bottom vnode is a directory, in which case 394df8bae1dSRodney W. Grimes * create a new directory in the top-level and 395df8bae1dSRodney W. Grimes * continue as in case 3. 396df8bae1dSRodney W. Grimes * 397df8bae1dSRodney W. Grimes * 3. if the top layer succeeded then return a new union 398df8bae1dSRodney W. Grimes * vnode referencing whatever the new top layer and 399df8bae1dSRodney W. Grimes * whatever the bottom layer returned. 400df8bae1dSRodney W. Grimes */ 401df8bae1dSRodney W. Grimes 402df8bae1dSRodney W. Grimes *ap->a_vpp = NULLVP; 403df8bae1dSRodney W. Grimes 404df8bae1dSRodney W. Grimes /* case 1. */ 405df8bae1dSRodney W. Grimes if ((uerror != 0) && (lerror != 0)) { 406df8bae1dSRodney W. Grimes return (uerror); 407df8bae1dSRodney W. Grimes } 408df8bae1dSRodney W. Grimes 409df8bae1dSRodney W. Grimes /* case 2. */ 410df8bae1dSRodney W. Grimes if (uerror != 0 /* && (lerror == 0) */ ) { 411df8bae1dSRodney W. Grimes if (lowervp->v_type == VDIR) { /* case 2b. */ 412df8bae1dSRodney W. Grimes dun->un_flags &= ~UN_ULOCK; 413996c772fSJohn Dyson VOP_UNLOCK(upperdvp, 0, p); 414df8bae1dSRodney W. Grimes uerror = union_mkshadow(um, upperdvp, cnp, &uppervp); 415996c772fSJohn Dyson vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p); 416df8bae1dSRodney W. Grimes dun->un_flags |= UN_ULOCK; 417df8bae1dSRodney W. Grimes 418df8bae1dSRodney W. Grimes if (uerror) { 419996c772fSJohn Dyson if (lowervp != NULLVP) { 420df8bae1dSRodney W. Grimes vput(lowervp); 421df8bae1dSRodney W. Grimes lowervp = NULLVP; 422df8bae1dSRodney W. Grimes } 423df8bae1dSRodney W. Grimes return (uerror); 424df8bae1dSRodney W. Grimes } 425df8bae1dSRodney W. Grimes } 426df8bae1dSRodney W. Grimes } 427df8bae1dSRodney W. Grimes 428996c772fSJohn Dyson if (lowervp != NULLVP) 429996c772fSJohn Dyson VOP_UNLOCK(lowervp, 0, p); 430df8bae1dSRodney W. Grimes 431df8bae1dSRodney W. Grimes error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, 432996c772fSJohn Dyson uppervp, lowervp, 1); 433df8bae1dSRodney W. Grimes 434df8bae1dSRodney W. Grimes if (error) { 435996c772fSJohn Dyson if (uppervp != NULLVP) 436df8bae1dSRodney W. Grimes vput(uppervp); 437996c772fSJohn Dyson if (lowervp != NULLVP) 438df8bae1dSRodney W. Grimes vrele(lowervp); 439df8bae1dSRodney W. Grimes } else { 440df8bae1dSRodney W. Grimes if (*ap->a_vpp != dvp) 441df8bae1dSRodney W. Grimes if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 442996c772fSJohn Dyson VOP_UNLOCK(dvp, 0, p); 443df8bae1dSRodney W. Grimes } 444df8bae1dSRodney W. Grimes 445df8bae1dSRodney W. Grimes return (error); 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes 448c9bf0111SKATO Takenori static int 449df8bae1dSRodney W. Grimes union_create(ap) 450df8bae1dSRodney W. Grimes struct vop_create_args /* { 451df8bae1dSRodney W. Grimes struct vnode *a_dvp; 452df8bae1dSRodney W. Grimes struct vnode **a_vpp; 453df8bae1dSRodney W. Grimes struct componentname *a_cnp; 454df8bae1dSRodney W. Grimes struct vattr *a_vap; 455df8bae1dSRodney W. Grimes } */ *ap; 456df8bae1dSRodney W. Grimes { 457df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_dvp); 458df8bae1dSRodney W. Grimes struct vnode *dvp = un->un_uppervp; 459996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 460996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 461df8bae1dSRodney W. Grimes 462996c772fSJohn Dyson if (dvp != NULLVP) { 463df8bae1dSRodney W. Grimes int error; 464df8bae1dSRodney W. Grimes struct vnode *vp; 465996c772fSJohn Dyson struct mount *mp; 466df8bae1dSRodney W. Grimes 467996c772fSJohn Dyson FIXUP(un, p); 468df8bae1dSRodney W. Grimes 469df8bae1dSRodney W. Grimes VREF(dvp); 470a9320ff3SKATO Takenori SETKLOCK(un); 471996c772fSJohn Dyson mp = ap->a_dvp->v_mount; 472df8bae1dSRodney W. Grimes vput(ap->a_dvp); 473a9320ff3SKATO Takenori CLEARKLOCK(un); 474996c772fSJohn Dyson error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap); 475df8bae1dSRodney W. Grimes if (error) 476df8bae1dSRodney W. Grimes return (error); 477df8bae1dSRodney W. Grimes 478996c772fSJohn Dyson error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp, 479996c772fSJohn Dyson NULLVP, 1); 480df8bae1dSRodney W. Grimes if (error) 481df8bae1dSRodney W. Grimes vput(vp); 482df8bae1dSRodney W. Grimes return (error); 483df8bae1dSRodney W. Grimes } 484df8bae1dSRodney W. Grimes 485df8bae1dSRodney W. Grimes vput(ap->a_dvp); 486df8bae1dSRodney W. Grimes return (EROFS); 487df8bae1dSRodney W. Grimes } 488df8bae1dSRodney W. Grimes 489c9bf0111SKATO Takenori static int 490996c772fSJohn Dyson union_whiteout(ap) 491996c772fSJohn Dyson struct vop_whiteout_args /* { 492996c772fSJohn Dyson struct vnode *a_dvp; 493996c772fSJohn Dyson struct componentname *a_cnp; 494996c772fSJohn Dyson int a_flags; 495996c772fSJohn Dyson } */ *ap; 496996c772fSJohn Dyson { 497996c772fSJohn Dyson struct union_node *un = VTOUNION(ap->a_dvp); 498996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 499996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 500996c772fSJohn Dyson 501996c772fSJohn Dyson if (un->un_uppervp == NULLVP) 502996c772fSJohn Dyson return (EOPNOTSUPP); 503996c772fSJohn Dyson 504996c772fSJohn Dyson FIXUP(un, p); 505996c772fSJohn Dyson return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags)); 506996c772fSJohn Dyson } 507996c772fSJohn Dyson 508c9bf0111SKATO Takenori static int 509df8bae1dSRodney W. Grimes union_mknod(ap) 510df8bae1dSRodney W. Grimes struct vop_mknod_args /* { 511df8bae1dSRodney W. Grimes struct vnode *a_dvp; 512df8bae1dSRodney W. Grimes struct vnode **a_vpp; 513df8bae1dSRodney W. Grimes struct componentname *a_cnp; 514df8bae1dSRodney W. Grimes struct vattr *a_vap; 515df8bae1dSRodney W. Grimes } */ *ap; 516df8bae1dSRodney W. Grimes { 517df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_dvp); 518df8bae1dSRodney W. Grimes struct vnode *dvp = un->un_uppervp; 519996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 520996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 521df8bae1dSRodney W. Grimes 522996c772fSJohn Dyson if (dvp != NULLVP) { 523df8bae1dSRodney W. Grimes int error; 524df8bae1dSRodney W. Grimes struct vnode *vp; 525996c772fSJohn Dyson struct mount *mp; 526df8bae1dSRodney W. Grimes 527996c772fSJohn Dyson FIXUP(un, p); 528df8bae1dSRodney W. Grimes 529df8bae1dSRodney W. Grimes VREF(dvp); 530a9320ff3SKATO Takenori SETKLOCK(un); 531996c772fSJohn Dyson mp = ap->a_dvp->v_mount; 532df8bae1dSRodney W. Grimes vput(ap->a_dvp); 533a9320ff3SKATO Takenori CLEARKLOCK(un); 534996c772fSJohn Dyson error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap); 535df8bae1dSRodney W. Grimes if (error) 536df8bae1dSRodney W. Grimes return (error); 537df8bae1dSRodney W. Grimes 538996c772fSJohn Dyson if (vp != NULLVP) { 539996c772fSJohn Dyson error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, 540996c772fSJohn Dyson cnp, vp, NULLVP, 1); 541df8bae1dSRodney W. Grimes if (error) 542df8bae1dSRodney W. Grimes vput(vp); 543df8bae1dSRodney W. Grimes } 544df8bae1dSRodney W. Grimes return (error); 545df8bae1dSRodney W. Grimes } 546df8bae1dSRodney W. Grimes 547df8bae1dSRodney W. Grimes vput(ap->a_dvp); 548df8bae1dSRodney W. Grimes return (EROFS); 549df8bae1dSRodney W. Grimes } 550df8bae1dSRodney W. Grimes 551c9bf0111SKATO Takenori static int 552df8bae1dSRodney W. Grimes union_open(ap) 553df8bae1dSRodney W. Grimes struct vop_open_args /* { 554df8bae1dSRodney W. Grimes struct vnodeop_desc *a_desc; 555df8bae1dSRodney W. Grimes struct vnode *a_vp; 556df8bae1dSRodney W. Grimes int a_mode; 557df8bae1dSRodney W. Grimes struct ucred *a_cred; 558df8bae1dSRodney W. Grimes struct proc *a_p; 559df8bae1dSRodney W. Grimes } */ *ap; 560df8bae1dSRodney W. Grimes { 561df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 562df8bae1dSRodney W. Grimes struct vnode *tvp; 563df8bae1dSRodney W. Grimes int mode = ap->a_mode; 564df8bae1dSRodney W. Grimes struct ucred *cred = ap->a_cred; 565df8bae1dSRodney W. Grimes struct proc *p = ap->a_p; 566df8bae1dSRodney W. Grimes int error; 567df8bae1dSRodney W. Grimes 568df8bae1dSRodney W. Grimes /* 569df8bae1dSRodney W. Grimes * If there is an existing upper vp then simply open that. 570df8bae1dSRodney W. Grimes */ 571df8bae1dSRodney W. Grimes tvp = un->un_uppervp; 572df8bae1dSRodney W. Grimes if (tvp == NULLVP) { 573df8bae1dSRodney W. Grimes /* 574df8bae1dSRodney W. Grimes * If the lower vnode is being opened for writing, then 575df8bae1dSRodney W. Grimes * copy the file contents to the upper vnode and open that, 576df8bae1dSRodney W. Grimes * otherwise can simply open the lower vnode. 577df8bae1dSRodney W. Grimes */ 578df8bae1dSRodney W. Grimes tvp = un->un_lowervp; 579df8bae1dSRodney W. Grimes if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { 580996c772fSJohn Dyson error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p); 581df8bae1dSRodney W. Grimes if (error == 0) 582df8bae1dSRodney W. Grimes error = VOP_OPEN(un->un_uppervp, mode, cred, p); 583df8bae1dSRodney W. Grimes return (error); 584df8bae1dSRodney W. Grimes } 585df8bae1dSRodney W. Grimes 586df8bae1dSRodney W. Grimes /* 587df8bae1dSRodney W. Grimes * Just open the lower vnode 588df8bae1dSRodney W. Grimes */ 589df8bae1dSRodney W. Grimes un->un_openl++; 590996c772fSJohn Dyson vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); 591df8bae1dSRodney W. Grimes error = VOP_OPEN(tvp, mode, cred, p); 592996c772fSJohn Dyson VOP_UNLOCK(tvp, 0, p); 593df8bae1dSRodney W. Grimes 594df8bae1dSRodney W. Grimes return (error); 595df8bae1dSRodney W. Grimes } 596df8bae1dSRodney W. Grimes 597996c772fSJohn Dyson FIXUP(un, p); 598df8bae1dSRodney W. Grimes 599df8bae1dSRodney W. Grimes error = VOP_OPEN(tvp, mode, cred, p); 600df8bae1dSRodney W. Grimes 601df8bae1dSRodney W. Grimes return (error); 602df8bae1dSRodney W. Grimes } 603df8bae1dSRodney W. Grimes 604c9bf0111SKATO Takenori static int 605df8bae1dSRodney W. Grimes union_close(ap) 606df8bae1dSRodney W. Grimes struct vop_close_args /* { 607df8bae1dSRodney W. Grimes struct vnode *a_vp; 608df8bae1dSRodney W. Grimes int a_fflag; 609df8bae1dSRodney W. Grimes struct ucred *a_cred; 610df8bae1dSRodney W. Grimes struct proc *a_p; 611df8bae1dSRodney W. Grimes } */ *ap; 612df8bae1dSRodney W. Grimes { 613df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 614df8bae1dSRodney W. Grimes struct vnode *vp; 615df8bae1dSRodney W. Grimes 616996c772fSJohn Dyson if ((vp = un->un_uppervp) == NULLVP) { 617df8bae1dSRodney W. Grimes #ifdef UNION_DIAGNOSTIC 618df8bae1dSRodney W. Grimes if (un->un_openl <= 0) 619df8bae1dSRodney W. Grimes panic("union: un_openl cnt"); 620df8bae1dSRodney W. Grimes #endif 621df8bae1dSRodney W. Grimes --un->un_openl; 622df8bae1dSRodney W. Grimes vp = un->un_lowervp; 623df8bae1dSRodney W. Grimes } 624df8bae1dSRodney W. Grimes 625996c772fSJohn Dyson ap->a_vp = vp; 626996c772fSJohn Dyson return (VCALL(vp, VOFFSET(vop_close), ap)); 627df8bae1dSRodney W. Grimes } 628df8bae1dSRodney W. Grimes 629df8bae1dSRodney W. Grimes /* 630df8bae1dSRodney W. Grimes * Check access permission on the union vnode. 631df8bae1dSRodney W. Grimes * The access check being enforced is to check 632df8bae1dSRodney W. Grimes * against both the underlying vnode, and any 633df8bae1dSRodney W. Grimes * copied vnode. This ensures that no additional 634df8bae1dSRodney W. Grimes * file permissions are given away simply because 635df8bae1dSRodney W. Grimes * the user caused an implicit file copy. 636df8bae1dSRodney W. Grimes */ 637c9bf0111SKATO Takenori static int 638df8bae1dSRodney W. Grimes union_access(ap) 639df8bae1dSRodney W. Grimes struct vop_access_args /* { 640df8bae1dSRodney W. Grimes struct vnodeop_desc *a_desc; 641df8bae1dSRodney W. Grimes struct vnode *a_vp; 642df8bae1dSRodney W. Grimes int a_mode; 643df8bae1dSRodney W. Grimes struct ucred *a_cred; 644df8bae1dSRodney W. Grimes struct proc *a_p; 645df8bae1dSRodney W. Grimes } */ *ap; 646df8bae1dSRodney W. Grimes { 647df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 648996c772fSJohn Dyson struct proc *p = ap->a_p; 649df8bae1dSRodney W. Grimes int error = EACCES; 650df8bae1dSRodney W. Grimes struct vnode *vp; 6515f3f68a8SKATO Takenori struct vnode *savedvp; 652df8bae1dSRodney W. Grimes 653996c772fSJohn Dyson if ((vp = un->un_uppervp) != NULLVP) { 654996c772fSJohn Dyson FIXUP(un, p); 655996c772fSJohn Dyson ap->a_vp = vp; 656996c772fSJohn Dyson return (VCALL(vp, VOFFSET(vop_access), ap)); 657df8bae1dSRodney W. Grimes } 658df8bae1dSRodney W. Grimes 659996c772fSJohn Dyson if ((vp = un->un_lowervp) != NULLVP) { 660996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 6615f3f68a8SKATO Takenori savedvp = ap->a_vp; 662996c772fSJohn Dyson ap->a_vp = vp; 663996c772fSJohn Dyson error = VCALL(vp, VOFFSET(vop_access), ap); 664df8bae1dSRodney W. Grimes if (error == 0) { 6655f3f68a8SKATO Takenori struct union_mount *um = MOUNTTOUNIONMOUNT(savedvp->v_mount); 666df8bae1dSRodney W. Grimes 667996c772fSJohn Dyson if (um->um_op == UNMNT_BELOW) { 668996c772fSJohn Dyson ap->a_cred = um->um_cred; 669996c772fSJohn Dyson error = VCALL(vp, VOFFSET(vop_access), ap); 670df8bae1dSRodney W. Grimes } 671996c772fSJohn Dyson } 672996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 673df8bae1dSRodney W. Grimes if (error) 674df8bae1dSRodney W. Grimes return (error); 675df8bae1dSRodney W. Grimes } 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes return (error); 678df8bae1dSRodney W. Grimes } 679df8bae1dSRodney W. Grimes 680df8bae1dSRodney W. Grimes /* 681996c772fSJohn Dyson * We handle getattr only to change the fsid and 682996c772fSJohn Dyson * track object sizes 683df8bae1dSRodney W. Grimes */ 684c9bf0111SKATO Takenori static int 685df8bae1dSRodney W. Grimes union_getattr(ap) 686df8bae1dSRodney W. Grimes struct vop_getattr_args /* { 687df8bae1dSRodney W. Grimes struct vnode *a_vp; 688df8bae1dSRodney W. Grimes struct vattr *a_vap; 689df8bae1dSRodney W. Grimes struct ucred *a_cred; 690df8bae1dSRodney W. Grimes struct proc *a_p; 691df8bae1dSRodney W. Grimes } */ *ap; 692df8bae1dSRodney W. Grimes { 693df8bae1dSRodney W. Grimes int error; 694df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 695df8bae1dSRodney W. Grimes struct vnode *vp = un->un_uppervp; 696996c772fSJohn Dyson struct proc *p = ap->a_p; 697df8bae1dSRodney W. Grimes struct vattr *vap; 698df8bae1dSRodney W. Grimes struct vattr va; 699df8bae1dSRodney W. Grimes 700df8bae1dSRodney W. Grimes 701df8bae1dSRodney W. Grimes /* 702df8bae1dSRodney W. Grimes * Some programs walk the filesystem hierarchy by counting 703df8bae1dSRodney W. Grimes * links to directories to avoid stat'ing all the time. 704df8bae1dSRodney W. Grimes * This means the link count on directories needs to be "correct". 705df8bae1dSRodney W. Grimes * The only way to do that is to call getattr on both layers 706df8bae1dSRodney W. Grimes * and fix up the link count. The link count will not necessarily 707df8bae1dSRodney W. Grimes * be accurate but will be large enough to defeat the tree walkers. 708df8bae1dSRodney W. Grimes */ 709df8bae1dSRodney W. Grimes 710df8bae1dSRodney W. Grimes vap = ap->a_vap; 711df8bae1dSRodney W. Grimes 712df8bae1dSRodney W. Grimes vp = un->un_uppervp; 713df8bae1dSRodney W. Grimes if (vp != NULLVP) { 714996c772fSJohn Dyson /* 715996c772fSJohn Dyson * It's not clear whether VOP_GETATTR is to be 716996c772fSJohn Dyson * called with the vnode locked or not. stat() calls 717996c772fSJohn Dyson * it with (vp) locked, and fstat calls it with 718996c772fSJohn Dyson * (vp) unlocked. 719996c772fSJohn Dyson * In the mean time, compensate here by checking 720996c772fSJohn Dyson * the union_node's lock flag. 721996c772fSJohn Dyson */ 722996c772fSJohn Dyson if (un->un_flags & UN_LOCKED) 723996c772fSJohn Dyson FIXUP(un, p); 724996c772fSJohn Dyson 725df8bae1dSRodney W. Grimes error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); 726df8bae1dSRodney W. Grimes if (error) 727df8bae1dSRodney W. Grimes return (error); 728996c772fSJohn Dyson union_newsize(ap->a_vp, vap->va_size, VNOVAL); 729df8bae1dSRodney W. Grimes } 730df8bae1dSRodney W. Grimes 731df8bae1dSRodney W. Grimes if (vp == NULLVP) { 732df8bae1dSRodney W. Grimes vp = un->un_lowervp; 733df8bae1dSRodney W. Grimes } else if (vp->v_type == VDIR) { 734df8bae1dSRodney W. Grimes vp = un->un_lowervp; 735df8bae1dSRodney W. Grimes vap = &va; 736df8bae1dSRodney W. Grimes } else { 737df8bae1dSRodney W. Grimes vp = NULLVP; 738df8bae1dSRodney W. Grimes } 739df8bae1dSRodney W. Grimes 740df8bae1dSRodney W. Grimes if (vp != NULLVP) { 741df8bae1dSRodney W. Grimes error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); 742df8bae1dSRodney W. Grimes if (error) 743df8bae1dSRodney W. Grimes return (error); 744996c772fSJohn Dyson union_newsize(ap->a_vp, VNOVAL, vap->va_size); 745df8bae1dSRodney W. Grimes } 746df8bae1dSRodney W. Grimes 747df8bae1dSRodney W. Grimes if ((vap != ap->a_vap) && (vap->va_type == VDIR)) 748df8bae1dSRodney W. Grimes ap->a_vap->va_nlink += vap->va_nlink; 749df8bae1dSRodney W. Grimes 750996c772fSJohn Dyson ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 751df8bae1dSRodney W. Grimes return (0); 752df8bae1dSRodney W. Grimes } 753df8bae1dSRodney W. Grimes 754c9bf0111SKATO Takenori static int 755df8bae1dSRodney W. Grimes union_setattr(ap) 756df8bae1dSRodney W. Grimes struct vop_setattr_args /* { 757df8bae1dSRodney W. Grimes struct vnode *a_vp; 758df8bae1dSRodney W. Grimes struct vattr *a_vap; 759df8bae1dSRodney W. Grimes struct ucred *a_cred; 760df8bae1dSRodney W. Grimes struct proc *a_p; 761df8bae1dSRodney W. Grimes } */ *ap; 762df8bae1dSRodney W. Grimes { 763df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 764996c772fSJohn Dyson struct proc *p = ap->a_p; 765df8bae1dSRodney W. Grimes int error; 766df8bae1dSRodney W. Grimes 767df8bae1dSRodney W. Grimes /* 768df8bae1dSRodney W. Grimes * Handle case of truncating lower object to zero size, 769df8bae1dSRodney W. Grimes * by creating a zero length upper object. This is to 770df8bae1dSRodney W. Grimes * handle the case of open with O_TRUNC and O_CREAT. 771df8bae1dSRodney W. Grimes */ 772df8bae1dSRodney W. Grimes if ((un->un_uppervp == NULLVP) && 773df8bae1dSRodney W. Grimes /* assert(un->un_lowervp != NULLVP) */ 774996c772fSJohn Dyson (un->un_lowervp->v_type == VREG)) { 775996c772fSJohn Dyson error = union_copyup(un, (ap->a_vap->va_size != 0), 776996c772fSJohn Dyson ap->a_cred, ap->a_p); 777df8bae1dSRodney W. Grimes if (error) 778df8bae1dSRodney W. Grimes return (error); 779df8bae1dSRodney W. Grimes } 780df8bae1dSRodney W. Grimes 781df8bae1dSRodney W. Grimes /* 782df8bae1dSRodney W. Grimes * Try to set attributes in upper layer, 783df8bae1dSRodney W. Grimes * otherwise return read-only filesystem error. 784df8bae1dSRodney W. Grimes */ 785df8bae1dSRodney W. Grimes if (un->un_uppervp != NULLVP) { 786996c772fSJohn Dyson FIXUP(un, p); 787df8bae1dSRodney W. Grimes error = VOP_SETATTR(un->un_uppervp, ap->a_vap, 788df8bae1dSRodney W. Grimes ap->a_cred, ap->a_p); 789996c772fSJohn Dyson if ((error == 0) && (ap->a_vap->va_size != VNOVAL)) 790996c772fSJohn Dyson union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL); 791df8bae1dSRodney W. Grimes } else { 792df8bae1dSRodney W. Grimes error = EROFS; 793df8bae1dSRodney W. Grimes } 794df8bae1dSRodney W. Grimes 795df8bae1dSRodney W. Grimes return (error); 796df8bae1dSRodney W. Grimes } 797df8bae1dSRodney W. Grimes 798c9bf0111SKATO Takenori static int 799df8bae1dSRodney W. Grimes union_read(ap) 800df8bae1dSRodney W. Grimes struct vop_read_args /* { 801df8bae1dSRodney W. Grimes struct vnode *a_vp; 802df8bae1dSRodney W. Grimes struct uio *a_uio; 803df8bae1dSRodney W. Grimes int a_ioflag; 804df8bae1dSRodney W. Grimes struct ucred *a_cred; 805df8bae1dSRodney W. Grimes } */ *ap; 806df8bae1dSRodney W. Grimes { 807df8bae1dSRodney W. Grimes int error; 808996c772fSJohn Dyson struct proc *p = ap->a_uio->uio_procp; 809df8bae1dSRodney W. Grimes struct vnode *vp = OTHERVP(ap->a_vp); 810df8bae1dSRodney W. Grimes int dolock = (vp == LOWERVP(ap->a_vp)); 811df8bae1dSRodney W. Grimes 812df8bae1dSRodney W. Grimes if (dolock) 813996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 814df8bae1dSRodney W. Grimes else 815996c772fSJohn Dyson FIXUP(VTOUNION(ap->a_vp), p); 816df8bae1dSRodney W. Grimes error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 817df8bae1dSRodney W. Grimes if (dolock) 818996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 819996c772fSJohn Dyson 820996c772fSJohn Dyson /* 821996c772fSJohn Dyson * XXX 822996c772fSJohn Dyson * perhaps the size of the underlying object has changed under 823996c772fSJohn Dyson * our feet. take advantage of the offset information present 824996c772fSJohn Dyson * in the uio structure. 825996c772fSJohn Dyson */ 826996c772fSJohn Dyson if (error == 0) { 827996c772fSJohn Dyson struct union_node *un = VTOUNION(ap->a_vp); 828996c772fSJohn Dyson off_t cur = ap->a_uio->uio_offset; 829996c772fSJohn Dyson 830996c772fSJohn Dyson if (vp == un->un_uppervp) { 831996c772fSJohn Dyson if (cur > un->un_uppersz) 832996c772fSJohn Dyson union_newsize(ap->a_vp, cur, VNOVAL); 833996c772fSJohn Dyson } else { 834996c772fSJohn Dyson if (cur > un->un_lowersz) 835996c772fSJohn Dyson union_newsize(ap->a_vp, VNOVAL, cur); 836996c772fSJohn Dyson } 837996c772fSJohn Dyson } 838df8bae1dSRodney W. Grimes 839df8bae1dSRodney W. Grimes return (error); 840df8bae1dSRodney W. Grimes } 841df8bae1dSRodney W. Grimes 842c9bf0111SKATO Takenori static int 843df8bae1dSRodney W. Grimes union_write(ap) 844df8bae1dSRodney W. Grimes struct vop_read_args /* { 845df8bae1dSRodney W. Grimes struct vnode *a_vp; 846df8bae1dSRodney W. Grimes struct uio *a_uio; 847df8bae1dSRodney W. Grimes int a_ioflag; 848df8bae1dSRodney W. Grimes struct ucred *a_cred; 849df8bae1dSRodney W. Grimes } */ *ap; 850df8bae1dSRodney W. Grimes { 851df8bae1dSRodney W. Grimes int error; 852996c772fSJohn Dyson struct vnode *vp; 853996c772fSJohn Dyson struct union_node *un = VTOUNION(ap->a_vp); 854996c772fSJohn Dyson struct proc *p = ap->a_uio->uio_procp; 855df8bae1dSRodney W. Grimes 856996c772fSJohn Dyson vp = UPPERVP(ap->a_vp); 857996c772fSJohn Dyson if (vp == NULLVP) 858996c772fSJohn Dyson panic("union: missing upper layer in write"); 859996c772fSJohn Dyson 860996c772fSJohn Dyson FIXUP(un, p); 861df8bae1dSRodney W. Grimes error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 862996c772fSJohn Dyson 863996c772fSJohn Dyson /* 864996c772fSJohn Dyson * the size of the underlying object may be changed by the 865996c772fSJohn Dyson * write. 866996c772fSJohn Dyson */ 867996c772fSJohn Dyson if (error == 0) { 868996c772fSJohn Dyson off_t cur = ap->a_uio->uio_offset; 869996c772fSJohn Dyson 870996c772fSJohn Dyson if (cur > un->un_uppersz) 871996c772fSJohn Dyson union_newsize(ap->a_vp, cur, VNOVAL); 872996c772fSJohn Dyson } 873df8bae1dSRodney W. Grimes 874df8bae1dSRodney W. Grimes return (error); 875df8bae1dSRodney W. Grimes } 876df8bae1dSRodney W. Grimes 877c9bf0111SKATO Takenori static int 878996c772fSJohn Dyson union_lease(ap) 879996c772fSJohn Dyson struct vop_lease_args /* { 880996c772fSJohn Dyson struct vnode *a_vp; 881996c772fSJohn Dyson struct proc *a_p; 882996c772fSJohn Dyson struct ucred *a_cred; 883996c772fSJohn Dyson int a_flag; 884996c772fSJohn Dyson } */ *ap; 885996c772fSJohn Dyson { 886996c772fSJohn Dyson register struct vnode *ovp = OTHERVP(ap->a_vp); 887996c772fSJohn Dyson 888996c772fSJohn Dyson ap->a_vp = ovp; 889996c772fSJohn Dyson return (VCALL(ovp, VOFFSET(vop_lease), ap)); 890996c772fSJohn Dyson } 891996c772fSJohn Dyson 892c9bf0111SKATO Takenori static int 893df8bae1dSRodney W. Grimes union_ioctl(ap) 894df8bae1dSRodney W. Grimes struct vop_ioctl_args /* { 895df8bae1dSRodney W. Grimes struct vnode *a_vp; 896df8bae1dSRodney W. Grimes int a_command; 897df8bae1dSRodney W. Grimes caddr_t a_data; 898df8bae1dSRodney W. Grimes int a_fflag; 899df8bae1dSRodney W. Grimes struct ucred *a_cred; 900df8bae1dSRodney W. Grimes struct proc *a_p; 901df8bae1dSRodney W. Grimes } */ *ap; 902df8bae1dSRodney W. Grimes { 903996c772fSJohn Dyson register struct vnode *ovp = OTHERVP(ap->a_vp); 904df8bae1dSRodney W. Grimes 905996c772fSJohn Dyson ap->a_vp = ovp; 906996c772fSJohn Dyson return (VCALL(ovp, VOFFSET(vop_ioctl), ap)); 907df8bae1dSRodney W. Grimes } 908df8bae1dSRodney W. Grimes 909c9bf0111SKATO Takenori static int 910df8bae1dSRodney W. Grimes union_select(ap) 911df8bae1dSRodney W. Grimes struct vop_select_args /* { 912df8bae1dSRodney W. Grimes struct vnode *a_vp; 913df8bae1dSRodney W. Grimes int a_which; 914df8bae1dSRodney W. Grimes int a_fflags; 915df8bae1dSRodney W. Grimes struct ucred *a_cred; 916df8bae1dSRodney W. Grimes struct proc *a_p; 917df8bae1dSRodney W. Grimes } */ *ap; 918df8bae1dSRodney W. Grimes { 919996c772fSJohn Dyson register struct vnode *ovp = OTHERVP(ap->a_vp); 920df8bae1dSRodney W. Grimes 921996c772fSJohn Dyson ap->a_vp = ovp; 922996c772fSJohn Dyson return (VCALL(ovp, VOFFSET(vop_select), ap)); 923996c772fSJohn Dyson } 924996c772fSJohn Dyson 925c9bf0111SKATO Takenori static int 926996c772fSJohn Dyson union_revoke(ap) 927996c772fSJohn Dyson struct vop_revoke_args /* { 928996c772fSJohn Dyson struct vnode *a_vp; 929996c772fSJohn Dyson int a_flags; 930996c772fSJohn Dyson struct proc *a_p; 931996c772fSJohn Dyson } */ *ap; 932996c772fSJohn Dyson { 933996c772fSJohn Dyson struct vnode *vp = ap->a_vp; 934996c772fSJohn Dyson 935996c772fSJohn Dyson if (UPPERVP(vp)) 936996c772fSJohn Dyson VOP_REVOKE(UPPERVP(vp), ap->a_flags); 937996c772fSJohn Dyson if (LOWERVP(vp)) 938996c772fSJohn Dyson VOP_REVOKE(LOWERVP(vp), ap->a_flags); 939996c772fSJohn Dyson vgone(vp); 940996c772fSJohn Dyson return (0); 941df8bae1dSRodney W. Grimes } 942df8bae1dSRodney W. Grimes 943c9bf0111SKATO Takenori static int 944df8bae1dSRodney W. Grimes union_mmap(ap) 945df8bae1dSRodney W. Grimes struct vop_mmap_args /* { 946df8bae1dSRodney W. Grimes struct vnode *a_vp; 947df8bae1dSRodney W. Grimes int a_fflags; 948df8bae1dSRodney W. Grimes struct ucred *a_cred; 949df8bae1dSRodney W. Grimes struct proc *a_p; 950df8bae1dSRodney W. Grimes } */ *ap; 951df8bae1dSRodney W. Grimes { 952996c772fSJohn Dyson register struct vnode *ovp = OTHERVP(ap->a_vp); 953df8bae1dSRodney W. Grimes 954996c772fSJohn Dyson ap->a_vp = ovp; 955996c772fSJohn Dyson return (VCALL(ovp, VOFFSET(vop_mmap), ap)); 956df8bae1dSRodney W. Grimes } 957df8bae1dSRodney W. Grimes 958c9bf0111SKATO Takenori static int 959df8bae1dSRodney W. Grimes union_fsync(ap) 960df8bae1dSRodney W. Grimes struct vop_fsync_args /* { 961df8bae1dSRodney W. Grimes struct vnode *a_vp; 962df8bae1dSRodney W. Grimes struct ucred *a_cred; 963df8bae1dSRodney W. Grimes int a_waitfor; 964df8bae1dSRodney W. Grimes struct proc *a_p; 965df8bae1dSRodney W. Grimes } */ *ap; 966df8bae1dSRodney W. Grimes { 967df8bae1dSRodney W. Grimes int error = 0; 968996c772fSJohn Dyson struct proc *p = ap->a_p; 969df8bae1dSRodney W. Grimes struct vnode *targetvp = OTHERVP(ap->a_vp); 970363ad700SPoul-Henning Kamp struct union_node *un; 971363ad700SPoul-Henning Kamp int isupperlocked = 0; 972df8bae1dSRodney W. Grimes 973996c772fSJohn Dyson if (targetvp != NULLVP) { 974df8bae1dSRodney W. Grimes int dolock = (targetvp == LOWERVP(ap->a_vp)); 975df8bae1dSRodney W. Grimes 976363ad700SPoul-Henning Kamp un = VTOUNION(ap->a_vp); 977df8bae1dSRodney W. Grimes if (dolock) 978996c772fSJohn Dyson vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p); 979363ad700SPoul-Henning Kamp else if ((un->un_flags & UN_ULOCK) == 0 && 980363ad700SPoul-Henning Kamp VOP_ISLOCKED(targetvp) == 0) { 981363ad700SPoul-Henning Kamp isupperlocked = 1; 982363ad700SPoul-Henning Kamp vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p); 983363ad700SPoul-Henning Kamp un->un_flags |= UN_ULOCK; 984363ad700SPoul-Henning Kamp } 985996c772fSJohn Dyson error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p); 986df8bae1dSRodney W. Grimes if (dolock) 987996c772fSJohn Dyson VOP_UNLOCK(targetvp, 0, p); 988363ad700SPoul-Henning Kamp else if (isupperlocked) { 989363ad700SPoul-Henning Kamp un->un_flags &= ~UN_ULOCK; 990a9320ff3SKATO Takenori VOP_UNLOCK(targetvp, 0, p); 991363ad700SPoul-Henning Kamp } 992df8bae1dSRodney W. Grimes } 993df8bae1dSRodney W. Grimes 994df8bae1dSRodney W. Grimes return (error); 995df8bae1dSRodney W. Grimes } 996df8bae1dSRodney W. Grimes 997c9bf0111SKATO Takenori static int 998df8bae1dSRodney W. Grimes union_seek(ap) 999df8bae1dSRodney W. Grimes struct vop_seek_args /* { 1000df8bae1dSRodney W. Grimes struct vnode *a_vp; 1001df8bae1dSRodney W. Grimes off_t a_oldoff; 1002df8bae1dSRodney W. Grimes off_t a_newoff; 1003df8bae1dSRodney W. Grimes struct ucred *a_cred; 1004df8bae1dSRodney W. Grimes } */ *ap; 1005df8bae1dSRodney W. Grimes { 1006996c772fSJohn Dyson register struct vnode *ovp = OTHERVP(ap->a_vp); 1007df8bae1dSRodney W. Grimes 1008996c772fSJohn Dyson ap->a_vp = ovp; 1009996c772fSJohn Dyson return (VCALL(ovp, VOFFSET(vop_seek), ap)); 1010df8bae1dSRodney W. Grimes } 1011df8bae1dSRodney W. Grimes 1012c9bf0111SKATO Takenori static int 1013df8bae1dSRodney W. Grimes union_remove(ap) 1014df8bae1dSRodney W. Grimes struct vop_remove_args /* { 1015df8bae1dSRodney W. Grimes struct vnode *a_dvp; 1016df8bae1dSRodney W. Grimes struct vnode *a_vp; 1017df8bae1dSRodney W. Grimes struct componentname *a_cnp; 1018df8bae1dSRodney W. Grimes } */ *ap; 1019df8bae1dSRodney W. Grimes { 1020df8bae1dSRodney W. Grimes int error; 1021df8bae1dSRodney W. Grimes struct union_node *dun = VTOUNION(ap->a_dvp); 1022df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 1023996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 1024996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 1025df8bae1dSRodney W. Grimes 1026996c772fSJohn Dyson if (dun->un_uppervp == NULLVP) 1027996c772fSJohn Dyson panic("union remove: null upper vnode"); 1028996c772fSJohn Dyson 1029996c772fSJohn Dyson if (un->un_uppervp != NULLVP) { 1030df8bae1dSRodney W. Grimes struct vnode *dvp = dun->un_uppervp; 1031df8bae1dSRodney W. Grimes struct vnode *vp = un->un_uppervp; 1032df8bae1dSRodney W. Grimes 1033996c772fSJohn Dyson FIXUP(dun, p); 1034df8bae1dSRodney W. Grimes VREF(dvp); 1035a9320ff3SKATO Takenori SETKLOCK(dun); 1036df8bae1dSRodney W. Grimes vput(ap->a_dvp); 1037a9320ff3SKATO Takenori CLEARKLOCK(dun); 1038996c772fSJohn Dyson FIXUP(un, p); 1039df8bae1dSRodney W. Grimes VREF(vp); 1040a9320ff3SKATO Takenori SETKLOCK(un); 1041df8bae1dSRodney W. Grimes vput(ap->a_vp); 1042a9320ff3SKATO Takenori CLEARKLOCK(un); 1043df8bae1dSRodney W. Grimes 1044996c772fSJohn Dyson if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc)) 1045996c772fSJohn Dyson cnp->cn_flags |= DOWHITEOUT; 1046996c772fSJohn Dyson error = VOP_REMOVE(dvp, vp, cnp); 1047df8bae1dSRodney W. Grimes if (!error) 1048df8bae1dSRodney W. Grimes union_removed_upper(un); 1049df8bae1dSRodney W. Grimes } else { 1050996c772fSJohn Dyson FIXUP(dun, p); 1051996c772fSJohn Dyson error = union_mkwhiteout( 1052996c772fSJohn Dyson MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), 1053996c772fSJohn Dyson dun->un_uppervp, ap->a_cnp, un->un_path); 1054df8bae1dSRodney W. Grimes vput(ap->a_dvp); 1055df8bae1dSRodney W. Grimes vput(ap->a_vp); 1056df8bae1dSRodney W. Grimes } 1057df8bae1dSRodney W. Grimes 1058df8bae1dSRodney W. Grimes return (error); 1059df8bae1dSRodney W. Grimes } 1060df8bae1dSRodney W. Grimes 1061c9bf0111SKATO Takenori static int 1062df8bae1dSRodney W. Grimes union_link(ap) 1063df8bae1dSRodney W. Grimes struct vop_link_args /* { 1064df8bae1dSRodney W. Grimes struct vnode *a_tdvp; 106547777413SDavid Greenman struct vnode *a_vp; 1066df8bae1dSRodney W. Grimes struct componentname *a_cnp; 1067df8bae1dSRodney W. Grimes } */ *ap; 1068df8bae1dSRodney W. Grimes { 1069996c772fSJohn Dyson int error = 0; 1070996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 1071996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 1072996c772fSJohn Dyson struct union_node *un; 1073996c772fSJohn Dyson struct vnode *vp; 1074996c772fSJohn Dyson struct vnode *tdvp; 1075df8bae1dSRodney W. Grimes 1076996c772fSJohn Dyson un = VTOUNION(ap->a_tdvp); 1077df8bae1dSRodney W. Grimes 1078996c772fSJohn Dyson if (ap->a_tdvp->v_op != ap->a_vp->v_op) { 1079996c772fSJohn Dyson vp = ap->a_vp; 1080df8bae1dSRodney W. Grimes } else { 1081996c772fSJohn Dyson struct union_node *tun = VTOUNION(ap->a_vp); 1082996c772fSJohn Dyson if (tun->un_uppervp == NULLVP) { 1083996c772fSJohn Dyson vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); 1084996c772fSJohn Dyson if (un->un_uppervp == tun->un_dirvp) { 1085996c772fSJohn Dyson un->un_flags &= ~UN_ULOCK; 1086996c772fSJohn Dyson VOP_UNLOCK(un->un_uppervp, 0, p); 1087996c772fSJohn Dyson } 1088996c772fSJohn Dyson error = union_copyup(tun, 1, cnp->cn_cred, p); 1089996c772fSJohn Dyson if (un->un_uppervp == tun->un_dirvp) { 1090996c772fSJohn Dyson vn_lock(un->un_uppervp, 1091996c772fSJohn Dyson LK_EXCLUSIVE | LK_RETRY, p); 1092996c772fSJohn Dyson un->un_flags |= UN_ULOCK; 1093996c772fSJohn Dyson } 1094996c772fSJohn Dyson VOP_UNLOCK(ap->a_vp, 0, p); 1095996c772fSJohn Dyson } 1096996c772fSJohn Dyson vp = tun->un_uppervp; 1097df8bae1dSRodney W. Grimes } 1098df8bae1dSRodney W. Grimes 1099996c772fSJohn Dyson tdvp = un->un_uppervp; 1100996c772fSJohn Dyson if (tdvp == NULLVP) 1101996c772fSJohn Dyson error = EROFS; 1102996c772fSJohn Dyson 1103996c772fSJohn Dyson if (error) { 1104996c772fSJohn Dyson vput(ap->a_tdvp); 1105df8bae1dSRodney W. Grimes return (error); 1106df8bae1dSRodney W. Grimes } 1107df8bae1dSRodney W. Grimes 1108996c772fSJohn Dyson FIXUP(un, p); 1109996c772fSJohn Dyson VREF(tdvp); 1110a9320ff3SKATO Takenori SETKLOCK(un); 1111996c772fSJohn Dyson vput(ap->a_tdvp); 1112a9320ff3SKATO Takenori CLEARKLOCK(un); 1113996c772fSJohn Dyson 111493d71a48SKATO Takenori return (VOP_LINK(tdvp, vp, cnp)); 1115996c772fSJohn Dyson } 1116996c772fSJohn Dyson 1117c9bf0111SKATO Takenori static int 1118df8bae1dSRodney W. Grimes union_rename(ap) 1119df8bae1dSRodney W. Grimes struct vop_rename_args /* { 1120df8bae1dSRodney W. Grimes struct vnode *a_fdvp; 1121df8bae1dSRodney W. Grimes struct vnode *a_fvp; 1122df8bae1dSRodney W. Grimes struct componentname *a_fcnp; 1123df8bae1dSRodney W. Grimes struct vnode *a_tdvp; 1124df8bae1dSRodney W. Grimes struct vnode *a_tvp; 1125df8bae1dSRodney W. Grimes struct componentname *a_tcnp; 1126df8bae1dSRodney W. Grimes } */ *ap; 1127df8bae1dSRodney W. Grimes { 1128df8bae1dSRodney W. Grimes int error; 1129df8bae1dSRodney W. Grimes 1130df8bae1dSRodney W. Grimes struct vnode *fdvp = ap->a_fdvp; 1131df8bae1dSRodney W. Grimes struct vnode *fvp = ap->a_fvp; 1132df8bae1dSRodney W. Grimes struct vnode *tdvp = ap->a_tdvp; 1133df8bae1dSRodney W. Grimes struct vnode *tvp = ap->a_tvp; 1134a9320ff3SKATO Takenori int isklockset = 0; 1135df8bae1dSRodney W. Grimes 1136df8bae1dSRodney W. Grimes if (fdvp->v_op == union_vnodeop_p) { /* always true */ 1137df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(fdvp); 1138df8bae1dSRodney W. Grimes if (un->un_uppervp == NULLVP) { 1139996c772fSJohn Dyson /* 1140996c772fSJohn Dyson * this should never happen in normal 1141996c772fSJohn Dyson * operation but might if there was 1142996c772fSJohn Dyson * a problem creating the top-level shadow 1143996c772fSJohn Dyson * directory. 1144996c772fSJohn Dyson */ 1145996c772fSJohn Dyson error = EXDEV; 1146df8bae1dSRodney W. Grimes goto bad; 1147df8bae1dSRodney W. Grimes } 1148df8bae1dSRodney W. Grimes 1149df8bae1dSRodney W. Grimes fdvp = un->un_uppervp; 1150df8bae1dSRodney W. Grimes VREF(fdvp); 1151df8bae1dSRodney W. Grimes vrele(ap->a_fdvp); 1152df8bae1dSRodney W. Grimes } 1153df8bae1dSRodney W. Grimes 1154df8bae1dSRodney W. Grimes if (fvp->v_op == union_vnodeop_p) { /* always true */ 1155df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(fvp); 1156df8bae1dSRodney W. Grimes if (un->un_uppervp == NULLVP) { 1157996c772fSJohn Dyson /* XXX: should do a copyup */ 1158996c772fSJohn Dyson error = EXDEV; 1159df8bae1dSRodney W. Grimes goto bad; 1160df8bae1dSRodney W. Grimes } 1161df8bae1dSRodney W. Grimes 1162996c772fSJohn Dyson if (un->un_lowervp != NULLVP) 1163996c772fSJohn Dyson ap->a_fcnp->cn_flags |= DOWHITEOUT; 1164996c772fSJohn Dyson 1165df8bae1dSRodney W. Grimes fvp = un->un_uppervp; 1166df8bae1dSRodney W. Grimes VREF(fvp); 1167df8bae1dSRodney W. Grimes vrele(ap->a_fvp); 1168df8bae1dSRodney W. Grimes } 1169df8bae1dSRodney W. Grimes 1170df8bae1dSRodney W. Grimes if (tdvp->v_op == union_vnodeop_p) { 1171df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(tdvp); 1172df8bae1dSRodney W. Grimes if (un->un_uppervp == NULLVP) { 1173996c772fSJohn Dyson /* 1174996c772fSJohn Dyson * this should never happen in normal 1175996c772fSJohn Dyson * operation but might if there was 1176996c772fSJohn Dyson * a problem creating the top-level shadow 1177996c772fSJohn Dyson * directory. 1178996c772fSJohn Dyson */ 1179996c772fSJohn Dyson error = EXDEV; 1180df8bae1dSRodney W. Grimes goto bad; 1181df8bae1dSRodney W. Grimes } 1182df8bae1dSRodney W. Grimes 1183df8bae1dSRodney W. Grimes tdvp = un->un_uppervp; 1184df8bae1dSRodney W. Grimes VREF(tdvp); 1185a9320ff3SKATO Takenori SETKLOCK(un); 1186df8bae1dSRodney W. Grimes vput(ap->a_tdvp); 1187a9320ff3SKATO Takenori CLEARKLOCK(un); 1188df8bae1dSRodney W. Grimes } 1189df8bae1dSRodney W. Grimes 1190996c772fSJohn Dyson if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) { 1191df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(tvp); 1192df8bae1dSRodney W. Grimes 1193df8bae1dSRodney W. Grimes tvp = un->un_uppervp; 1194996c772fSJohn Dyson if (tvp != NULLVP) { 1195df8bae1dSRodney W. Grimes VREF(tvp); 1196a9320ff3SKATO Takenori SETKLOCK(un); 1197a9320ff3SKATO Takenori isklockset = 1; 1198996c772fSJohn Dyson } 1199df8bae1dSRodney W. Grimes vput(ap->a_tvp); 1200a9320ff3SKATO Takenori if (isklockset) 1201a9320ff3SKATO Takenori CLEARKLOCK(un); 1202df8bae1dSRodney W. Grimes } 1203df8bae1dSRodney W. Grimes 1204df8bae1dSRodney W. Grimes return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); 1205df8bae1dSRodney W. Grimes 1206df8bae1dSRodney W. Grimes bad: 1207df8bae1dSRodney W. Grimes vrele(fdvp); 1208df8bae1dSRodney W. Grimes vrele(fvp); 1209df8bae1dSRodney W. Grimes vput(tdvp); 1210996c772fSJohn Dyson if (tvp != NULLVP) 1211df8bae1dSRodney W. Grimes vput(tvp); 1212df8bae1dSRodney W. Grimes 1213df8bae1dSRodney W. Grimes return (error); 1214df8bae1dSRodney W. Grimes } 1215df8bae1dSRodney W. Grimes 1216c9bf0111SKATO Takenori static int 1217df8bae1dSRodney W. Grimes union_mkdir(ap) 1218df8bae1dSRodney W. Grimes struct vop_mkdir_args /* { 1219df8bae1dSRodney W. Grimes struct vnode *a_dvp; 1220df8bae1dSRodney W. Grimes struct vnode **a_vpp; 1221df8bae1dSRodney W. Grimes struct componentname *a_cnp; 1222df8bae1dSRodney W. Grimes struct vattr *a_vap; 1223df8bae1dSRodney W. Grimes } */ *ap; 1224df8bae1dSRodney W. Grimes { 1225df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_dvp); 1226df8bae1dSRodney W. Grimes struct vnode *dvp = un->un_uppervp; 1227996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 1228996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 1229df8bae1dSRodney W. Grimes 1230996c772fSJohn Dyson if (dvp != NULLVP) { 1231df8bae1dSRodney W. Grimes int error; 1232df8bae1dSRodney W. Grimes struct vnode *vp; 1233df8bae1dSRodney W. Grimes 1234996c772fSJohn Dyson FIXUP(un, p); 1235df8bae1dSRodney W. Grimes VREF(dvp); 1236a9320ff3SKATO Takenori SETKLOCK(un); 1237996c772fSJohn Dyson VOP_UNLOCK(ap->a_dvp, 0, p); 1238a9320ff3SKATO Takenori CLEARKLOCK(un); 1239996c772fSJohn Dyson error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap); 1240996c772fSJohn Dyson if (error) { 1241996c772fSJohn Dyson vrele(ap->a_dvp); 1242df8bae1dSRodney W. Grimes return (error); 1243996c772fSJohn Dyson } 1244df8bae1dSRodney W. Grimes 1245996c772fSJohn Dyson error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp, 1246996c772fSJohn Dyson NULLVP, cnp, vp, NULLVP, 1); 1247996c772fSJohn Dyson vrele(ap->a_dvp); 1248df8bae1dSRodney W. Grimes if (error) 1249df8bae1dSRodney W. Grimes vput(vp); 1250df8bae1dSRodney W. Grimes return (error); 1251df8bae1dSRodney W. Grimes } 1252df8bae1dSRodney W. Grimes 1253df8bae1dSRodney W. Grimes vput(ap->a_dvp); 1254df8bae1dSRodney W. Grimes return (EROFS); 1255df8bae1dSRodney W. Grimes } 1256df8bae1dSRodney W. Grimes 1257c9bf0111SKATO Takenori static int 1258df8bae1dSRodney W. Grimes union_rmdir(ap) 1259df8bae1dSRodney W. Grimes struct vop_rmdir_args /* { 1260df8bae1dSRodney W. Grimes struct vnode *a_dvp; 1261df8bae1dSRodney W. Grimes struct vnode *a_vp; 1262df8bae1dSRodney W. Grimes struct componentname *a_cnp; 1263df8bae1dSRodney W. Grimes } */ *ap; 1264df8bae1dSRodney W. Grimes { 1265df8bae1dSRodney W. Grimes int error; 1266df8bae1dSRodney W. Grimes struct union_node *dun = VTOUNION(ap->a_dvp); 1267df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 1268996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 1269996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 1270df8bae1dSRodney W. Grimes 1271996c772fSJohn Dyson if (dun->un_uppervp == NULLVP) 1272996c772fSJohn Dyson panic("union rmdir: null upper vnode"); 1273996c772fSJohn Dyson 1274996c772fSJohn Dyson if (un->un_uppervp != NULLVP) { 1275df8bae1dSRodney W. Grimes struct vnode *dvp = dun->un_uppervp; 1276df8bae1dSRodney W. Grimes struct vnode *vp = un->un_uppervp; 1277df8bae1dSRodney W. Grimes 1278996c772fSJohn Dyson FIXUP(dun, p); 1279df8bae1dSRodney W. Grimes VREF(dvp); 1280a9320ff3SKATO Takenori SETKLOCK(dun); 1281df8bae1dSRodney W. Grimes vput(ap->a_dvp); 1282a9320ff3SKATO Takenori CLEARKLOCK(dun); 1283996c772fSJohn Dyson FIXUP(un, p); 1284df8bae1dSRodney W. Grimes VREF(vp); 1285a9320ff3SKATO Takenori SETKLOCK(un); 1286df8bae1dSRodney W. Grimes vput(ap->a_vp); 1287a9320ff3SKATO Takenori CLEARKLOCK(un); 1288df8bae1dSRodney W. Grimes 1289996c772fSJohn Dyson if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc)) 1290996c772fSJohn Dyson cnp->cn_flags |= DOWHITEOUT; 1291df8bae1dSRodney W. Grimes error = VOP_RMDIR(dvp, vp, ap->a_cnp); 1292df8bae1dSRodney W. Grimes if (!error) 1293df8bae1dSRodney W. Grimes union_removed_upper(un); 1294df8bae1dSRodney W. Grimes } else { 1295996c772fSJohn Dyson FIXUP(dun, p); 1296996c772fSJohn Dyson error = union_mkwhiteout( 1297996c772fSJohn Dyson MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount), 1298996c772fSJohn Dyson dun->un_uppervp, ap->a_cnp, un->un_path); 1299df8bae1dSRodney W. Grimes vput(ap->a_dvp); 1300df8bae1dSRodney W. Grimes vput(ap->a_vp); 1301df8bae1dSRodney W. Grimes } 1302df8bae1dSRodney W. Grimes 1303df8bae1dSRodney W. Grimes return (error); 1304df8bae1dSRodney W. Grimes } 1305df8bae1dSRodney W. Grimes 1306c9bf0111SKATO Takenori static int 1307df8bae1dSRodney W. Grimes union_symlink(ap) 1308df8bae1dSRodney W. Grimes struct vop_symlink_args /* { 1309df8bae1dSRodney W. Grimes struct vnode *a_dvp; 1310df8bae1dSRodney W. Grimes struct vnode **a_vpp; 1311df8bae1dSRodney W. Grimes struct componentname *a_cnp; 1312df8bae1dSRodney W. Grimes struct vattr *a_vap; 1313df8bae1dSRodney W. Grimes char *a_target; 1314df8bae1dSRodney W. Grimes } */ *ap; 1315df8bae1dSRodney W. Grimes { 1316df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_dvp); 1317df8bae1dSRodney W. Grimes struct vnode *dvp = un->un_uppervp; 1318996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 1319996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 1320df8bae1dSRodney W. Grimes 1321996c772fSJohn Dyson if (dvp != NULLVP) { 1322df8bae1dSRodney W. Grimes int error; 1323df8bae1dSRodney W. Grimes struct vnode *vp; 1324df8bae1dSRodney W. Grimes 1325996c772fSJohn Dyson FIXUP(un, p); 1326df8bae1dSRodney W. Grimes VREF(dvp); 1327a9320ff3SKATO Takenori SETKLOCK(un); 1328df8bae1dSRodney W. Grimes vput(ap->a_dvp); 1329a9320ff3SKATO Takenori CLEARKLOCK(un); 1330996c772fSJohn Dyson error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target); 1331df8bae1dSRodney W. Grimes *ap->a_vpp = NULLVP; 1332df8bae1dSRodney W. Grimes return (error); 1333df8bae1dSRodney W. Grimes } 1334df8bae1dSRodney W. Grimes 1335df8bae1dSRodney W. Grimes vput(ap->a_dvp); 1336df8bae1dSRodney W. Grimes return (EROFS); 1337df8bae1dSRodney W. Grimes } 1338df8bae1dSRodney W. Grimes 1339df8bae1dSRodney W. Grimes /* 1340df8bae1dSRodney W. Grimes * union_readdir works in concert with getdirentries and 1341df8bae1dSRodney W. Grimes * readdir(3) to provide a list of entries in the unioned 1342df8bae1dSRodney W. Grimes * directories. getdirentries is responsible for walking 1343df8bae1dSRodney W. Grimes * down the union stack. readdir(3) is responsible for 1344df8bae1dSRodney W. Grimes * eliminating duplicate names from the returned data stream. 1345df8bae1dSRodney W. Grimes */ 1346c9bf0111SKATO Takenori static int 1347df8bae1dSRodney W. Grimes union_readdir(ap) 1348df8bae1dSRodney W. Grimes struct vop_readdir_args /* { 1349df8bae1dSRodney W. Grimes struct vnode *a_vp; 1350df8bae1dSRodney W. Grimes struct uio *a_uio; 1351df8bae1dSRodney W. Grimes struct ucred *a_cred; 1352996c772fSJohn Dyson int *a_eofflag; 1353996c772fSJohn Dyson u_long *a_cookies; 1354996c772fSJohn Dyson int a_ncookies; 1355df8bae1dSRodney W. Grimes } */ *ap; 1356df8bae1dSRodney W. Grimes { 1357df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 1358996c772fSJohn Dyson struct vnode *uvp = un->un_uppervp; 1359996c772fSJohn Dyson struct proc *p = ap->a_uio->uio_procp; 1360df8bae1dSRodney W. Grimes 1361996c772fSJohn Dyson if (uvp == NULLVP) 1362996c772fSJohn Dyson return (0); 1363df8bae1dSRodney W. Grimes 1364996c772fSJohn Dyson FIXUP(un, p); 1365996c772fSJohn Dyson ap->a_vp = uvp; 1366996c772fSJohn Dyson return (VCALL(uvp, VOFFSET(vop_readdir), ap)); 1367df8bae1dSRodney W. Grimes } 1368df8bae1dSRodney W. Grimes 1369c9bf0111SKATO Takenori static int 1370df8bae1dSRodney W. Grimes union_readlink(ap) 1371df8bae1dSRodney W. Grimes struct vop_readlink_args /* { 1372df8bae1dSRodney W. Grimes struct vnode *a_vp; 1373df8bae1dSRodney W. Grimes struct uio *a_uio; 1374df8bae1dSRodney W. Grimes struct ucred *a_cred; 1375df8bae1dSRodney W. Grimes } */ *ap; 1376df8bae1dSRodney W. Grimes { 1377df8bae1dSRodney W. Grimes int error; 1378996c772fSJohn Dyson struct uio *uio = ap->a_uio; 1379996c772fSJohn Dyson struct proc *p = uio->uio_procp; 1380df8bae1dSRodney W. Grimes struct vnode *vp = OTHERVP(ap->a_vp); 1381df8bae1dSRodney W. Grimes int dolock = (vp == LOWERVP(ap->a_vp)); 1382df8bae1dSRodney W. Grimes 1383df8bae1dSRodney W. Grimes if (dolock) 1384996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1385df8bae1dSRodney W. Grimes else 1386996c772fSJohn Dyson FIXUP(VTOUNION(ap->a_vp), p); 1387996c772fSJohn Dyson ap->a_vp = vp; 1388996c772fSJohn Dyson error = VCALL(vp, VOFFSET(vop_readlink), ap); 1389df8bae1dSRodney W. Grimes if (dolock) 1390996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1391df8bae1dSRodney W. Grimes 1392df8bae1dSRodney W. Grimes return (error); 1393df8bae1dSRodney W. Grimes } 1394df8bae1dSRodney W. Grimes 1395c9bf0111SKATO Takenori static int 1396df8bae1dSRodney W. Grimes union_abortop(ap) 1397df8bae1dSRodney W. Grimes struct vop_abortop_args /* { 1398df8bae1dSRodney W. Grimes struct vnode *a_dvp; 1399df8bae1dSRodney W. Grimes struct componentname *a_cnp; 1400df8bae1dSRodney W. Grimes } */ *ap; 1401df8bae1dSRodney W. Grimes { 1402df8bae1dSRodney W. Grimes int error; 1403996c772fSJohn Dyson struct componentname *cnp = ap->a_cnp; 1404996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 1405df8bae1dSRodney W. Grimes struct vnode *vp = OTHERVP(ap->a_dvp); 1406df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_dvp); 1407df8bae1dSRodney W. Grimes int islocked = un->un_flags & UN_LOCKED; 1408df8bae1dSRodney W. Grimes int dolock = (vp == LOWERVP(ap->a_dvp)); 1409df8bae1dSRodney W. Grimes 1410df8bae1dSRodney W. Grimes if (islocked) { 1411df8bae1dSRodney W. Grimes if (dolock) 1412996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1413df8bae1dSRodney W. Grimes else 1414996c772fSJohn Dyson FIXUP(VTOUNION(ap->a_dvp), p); 1415df8bae1dSRodney W. Grimes } 1416996c772fSJohn Dyson ap->a_dvp = vp; 1417996c772fSJohn Dyson error = VCALL(vp, VOFFSET(vop_abortop), ap); 1418df8bae1dSRodney W. Grimes if (islocked && dolock) 1419996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1420df8bae1dSRodney W. Grimes 1421df8bae1dSRodney W. Grimes return (error); 1422df8bae1dSRodney W. Grimes } 1423df8bae1dSRodney W. Grimes 1424c9bf0111SKATO Takenori static int 1425df8bae1dSRodney W. Grimes union_inactive(ap) 1426df8bae1dSRodney W. Grimes struct vop_inactive_args /* { 1427df8bae1dSRodney W. Grimes struct vnode *a_vp; 1428996c772fSJohn Dyson struct proc *a_p; 1429df8bae1dSRodney W. Grimes } */ *ap; 1430df8bae1dSRodney W. Grimes { 1431996c772fSJohn Dyson struct vnode *vp = ap->a_vp; 1432996c772fSJohn Dyson struct proc *p = ap->a_p; 1433996c772fSJohn Dyson struct union_node *un = VTOUNION(vp); 1434996c772fSJohn Dyson struct vnode **vpp; 1435df8bae1dSRodney W. Grimes 1436df8bae1dSRodney W. Grimes /* 1437df8bae1dSRodney W. Grimes * Do nothing (and _don't_ bypass). 1438df8bae1dSRodney W. Grimes * Wait to vrele lowervp until reclaim, 1439df8bae1dSRodney W. Grimes * so that until then our union_node is in the 1440df8bae1dSRodney W. Grimes * cache and reusable. 1441df8bae1dSRodney W. Grimes * 1442df8bae1dSRodney W. Grimes * NEEDSWORK: Someday, consider inactive'ing 1443df8bae1dSRodney W. Grimes * the lowervp and then trying to reactivate it 1444df8bae1dSRodney W. Grimes * with capabilities (v_id) 1445df8bae1dSRodney W. Grimes * like they do in the name lookup cache code. 1446df8bae1dSRodney W. Grimes * That's too much work for now. 1447df8bae1dSRodney W. Grimes */ 1448df8bae1dSRodney W. Grimes 1449996c772fSJohn Dyson if (un->un_dircache != 0) { 1450996c772fSJohn Dyson for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) 1451996c772fSJohn Dyson vrele(*vpp); 1452996c772fSJohn Dyson free(un->un_dircache, M_TEMP); 1453996c772fSJohn Dyson un->un_dircache = 0; 1454996c772fSJohn Dyson } 1455df8bae1dSRodney W. Grimes 1456996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1457996c772fSJohn Dyson 1458996c772fSJohn Dyson if ((un->un_flags & UN_CACHED) == 0) 1459996c772fSJohn Dyson vgone(vp); 1460df8bae1dSRodney W. Grimes 1461df8bae1dSRodney W. Grimes return (0); 1462df8bae1dSRodney W. Grimes } 1463df8bae1dSRodney W. Grimes 1464c9bf0111SKATO Takenori static int 1465df8bae1dSRodney W. Grimes union_reclaim(ap) 1466df8bae1dSRodney W. Grimes struct vop_reclaim_args /* { 1467df8bae1dSRodney W. Grimes struct vnode *a_vp; 1468df8bae1dSRodney W. Grimes } */ *ap; 1469df8bae1dSRodney W. Grimes { 1470df8bae1dSRodney W. Grimes 1471df8bae1dSRodney W. Grimes union_freevp(ap->a_vp); 1472df8bae1dSRodney W. Grimes 1473df8bae1dSRodney W. Grimes return (0); 1474df8bae1dSRodney W. Grimes } 1475df8bae1dSRodney W. Grimes 1476c9bf0111SKATO Takenori static int 1477df8bae1dSRodney W. Grimes union_lock(ap) 1478df8bae1dSRodney W. Grimes struct vop_lock_args *ap; 1479df8bae1dSRodney W. Grimes { 1480df8bae1dSRodney W. Grimes struct vnode *vp = ap->a_vp; 1481996c772fSJohn Dyson struct proc *p = ap->a_p; 1482996c772fSJohn Dyson int flags = ap->a_flags; 1483df8bae1dSRodney W. Grimes struct union_node *un; 1484996c772fSJohn Dyson int error; 1485996c772fSJohn Dyson 1486996c772fSJohn Dyson vop_nolock(ap); 1487996c772fSJohn Dyson /* 1488996c772fSJohn Dyson * Need to do real lockmgr-style locking here. 1489996c772fSJohn Dyson * in the mean time, draining won't work quite right, 1490996c772fSJohn Dyson * which could lead to a few race conditions. 1491996c772fSJohn Dyson * the following test was here, but is not quite right, we 1492996c772fSJohn Dyson * still need to take the lock: 1493996c772fSJohn Dyson if ((flags & LK_TYPE_MASK) == LK_DRAIN) 1494996c772fSJohn Dyson return (0); 1495996c772fSJohn Dyson */ 1496996c772fSJohn Dyson flags &= ~LK_INTERLOCK; 1497df8bae1dSRodney W. Grimes 1498df8bae1dSRodney W. Grimes start: 1499df8bae1dSRodney W. Grimes un = VTOUNION(vp); 1500df8bae1dSRodney W. Grimes 1501996c772fSJohn Dyson if (un->un_uppervp != NULLVP) { 1502a9320ff3SKATO Takenori if (((un->un_flags & (UN_ULOCK | UN_KLOCK)) == 0) && 1503996c772fSJohn Dyson (vp->v_usecount != 0)) { 1504c9bf0111SKATO Takenori if (0 && VOP_ISLOCKED(un->un_uppervp)) { 150518b4c8e2SKATO Takenori /* 1506a9320ff3SKATO Takenori * XXX 1507a18ac0ffSKATO Takenori * Erm, we find race! 150818b4c8e2SKATO Takenori */ 150918b4c8e2SKATO Takenori #ifdef DIAGNOSTIC 151032cfb899SKATO Takenori panic("union_lock: upper vnode is locked, " 151118b4c8e2SKATO Takenori "but UN_UNLOCK is not set."); 151218b4c8e2SKATO Takenori #endif 1513a9320ff3SKATO Takenori un->un_flags |= UN_ULOCK; 151418b4c8e2SKATO Takenori } else { 1515996c772fSJohn Dyson error = vn_lock(un->un_uppervp, flags, p); 1516996c772fSJohn Dyson if (error) 1517996c772fSJohn Dyson return (error); 1518df8bae1dSRodney W. Grimes un->un_flags |= UN_ULOCK; 1519df8bae1dSRodney W. Grimes } 152018b4c8e2SKATO Takenori } 1521df8bae1dSRodney W. Grimes } 1522df8bae1dSRodney W. Grimes 1523df8bae1dSRodney W. Grimes if (un->un_flags & UN_LOCKED) { 1524df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1525df8bae1dSRodney W. Grimes if (curproc && un->un_pid == curproc->p_pid && 1526df8bae1dSRodney W. Grimes un->un_pid > -1 && curproc->p_pid > -1) 1527df8bae1dSRodney W. Grimes panic("union: locking against myself"); 1528df8bae1dSRodney W. Grimes #endif 1529df8bae1dSRodney W. Grimes un->un_flags |= UN_WANT; 1530996c772fSJohn Dyson tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0); 1531df8bae1dSRodney W. Grimes goto start; 1532df8bae1dSRodney W. Grimes } 1533df8bae1dSRodney W. Grimes 1534df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1535df8bae1dSRodney W. Grimes if (curproc) 1536df8bae1dSRodney W. Grimes un->un_pid = curproc->p_pid; 1537df8bae1dSRodney W. Grimes else 1538df8bae1dSRodney W. Grimes un->un_pid = -1; 1539df8bae1dSRodney W. Grimes #endif 1540df8bae1dSRodney W. Grimes 1541df8bae1dSRodney W. Grimes un->un_flags |= UN_LOCKED; 1542df8bae1dSRodney W. Grimes return (0); 1543df8bae1dSRodney W. Grimes } 1544df8bae1dSRodney W. Grimes 1545996c772fSJohn Dyson /* 1546996c772fSJohn Dyson * When operations want to vput() a union node yet retain a lock on 1547996c772fSJohn Dyson * the upper vnode (say, to do some further operations like link(), 1548996c772fSJohn Dyson * mkdir(), ...), they set UN_KLOCK on the union node, then call 1549996c772fSJohn Dyson * vput() which calls VOP_UNLOCK() and comes here. union_unlock() 1550996c772fSJohn Dyson * unlocks the union node (leaving the upper vnode alone), clears the 1551996c772fSJohn Dyson * KLOCK flag, and then returns to vput(). The caller then does whatever 1552996c772fSJohn Dyson * is left to do with the upper vnode, and ensures that it gets unlocked. 1553996c772fSJohn Dyson * 1554996c772fSJohn Dyson * If UN_KLOCK isn't set, then the upper vnode is unlocked here. 1555996c772fSJohn Dyson */ 1556c9bf0111SKATO Takenori static int 1557df8bae1dSRodney W. Grimes union_unlock(ap) 1558996c772fSJohn Dyson struct vop_unlock_args /* { 1559996c772fSJohn Dyson struct vnode *a_vp; 1560996c772fSJohn Dyson int a_flags; 1561996c772fSJohn Dyson struct proc *a_p; 1562996c772fSJohn Dyson } */ *ap; 1563df8bae1dSRodney W. Grimes { 1564df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(ap->a_vp); 1565996c772fSJohn Dyson struct proc *p = ap->a_p; 1566df8bae1dSRodney W. Grimes 1567df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1568df8bae1dSRodney W. Grimes if ((un->un_flags & UN_LOCKED) == 0) 1569df8bae1dSRodney W. Grimes panic("union: unlock unlocked node"); 1570df8bae1dSRodney W. Grimes if (curproc && un->un_pid != curproc->p_pid && 1571df8bae1dSRodney W. Grimes curproc->p_pid > -1 && un->un_pid > -1) 1572df8bae1dSRodney W. Grimes panic("union: unlocking other process's union node"); 1573df8bae1dSRodney W. Grimes #endif 1574df8bae1dSRodney W. Grimes 1575df8bae1dSRodney W. Grimes un->un_flags &= ~UN_LOCKED; 1576df8bae1dSRodney W. Grimes 1577df8bae1dSRodney W. Grimes if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK) 1578996c772fSJohn Dyson VOP_UNLOCK(un->un_uppervp, 0, p); 1579df8bae1dSRodney W. Grimes 1580a9320ff3SKATO Takenori un->un_flags &= ~UN_ULOCK; 1581df8bae1dSRodney W. Grimes 1582df8bae1dSRodney W. Grimes if (un->un_flags & UN_WANT) { 1583df8bae1dSRodney W. Grimes un->un_flags &= ~UN_WANT; 1584df8bae1dSRodney W. Grimes wakeup((caddr_t) &un->un_flags); 1585df8bae1dSRodney W. Grimes } 1586df8bae1dSRodney W. Grimes 1587df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1588df8bae1dSRodney W. Grimes un->un_pid = 0; 1589df8bae1dSRodney W. Grimes #endif 1590996c772fSJohn Dyson vop_nounlock(ap); 1591df8bae1dSRodney W. Grimes 1592df8bae1dSRodney W. Grimes return (0); 1593df8bae1dSRodney W. Grimes } 1594df8bae1dSRodney W. Grimes 1595c9bf0111SKATO Takenori static int 1596df8bae1dSRodney W. Grimes union_bmap(ap) 1597df8bae1dSRodney W. Grimes struct vop_bmap_args /* { 1598df8bae1dSRodney W. Grimes struct vnode *a_vp; 1599df8bae1dSRodney W. Grimes daddr_t a_bn; 1600df8bae1dSRodney W. Grimes struct vnode **a_vpp; 1601df8bae1dSRodney W. Grimes daddr_t *a_bnp; 1602df8bae1dSRodney W. Grimes int *a_runp; 1603c83ebe77SJohn Dyson int *a_runb; 1604df8bae1dSRodney W. Grimes } */ *ap; 1605df8bae1dSRodney W. Grimes { 1606df8bae1dSRodney W. Grimes int error; 1607996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1608df8bae1dSRodney W. Grimes struct vnode *vp = OTHERVP(ap->a_vp); 1609df8bae1dSRodney W. Grimes int dolock = (vp == LOWERVP(ap->a_vp)); 1610df8bae1dSRodney W. Grimes 1611df8bae1dSRodney W. Grimes if (dolock) 1612996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1613df8bae1dSRodney W. Grimes else 1614996c772fSJohn Dyson FIXUP(VTOUNION(ap->a_vp), p); 1615996c772fSJohn Dyson ap->a_vp = vp; 1616996c772fSJohn Dyson error = VCALL(vp, VOFFSET(vop_bmap), ap); 1617df8bae1dSRodney W. Grimes if (dolock) 1618996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1619df8bae1dSRodney W. Grimes 1620df8bae1dSRodney W. Grimes return (error); 1621df8bae1dSRodney W. Grimes } 1622df8bae1dSRodney W. Grimes 1623c9bf0111SKATO Takenori static int 1624df8bae1dSRodney W. Grimes union_print(ap) 1625df8bae1dSRodney W. Grimes struct vop_print_args /* { 1626df8bae1dSRodney W. Grimes struct vnode *a_vp; 1627df8bae1dSRodney W. Grimes } */ *ap; 1628df8bae1dSRodney W. Grimes { 1629df8bae1dSRodney W. Grimes struct vnode *vp = ap->a_vp; 1630df8bae1dSRodney W. Grimes 16313a773ad0SPoul-Henning Kamp printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n", 1632df8bae1dSRodney W. Grimes vp, UPPERVP(vp), LOWERVP(vp)); 1633996c772fSJohn Dyson if (UPPERVP(vp) != NULLVP) 1634996c772fSJohn Dyson vprint("union: upper", UPPERVP(vp)); 1635996c772fSJohn Dyson if (LOWERVP(vp) != NULLVP) 1636996c772fSJohn Dyson vprint("union: lower", LOWERVP(vp)); 1637996c772fSJohn Dyson 1638df8bae1dSRodney W. Grimes return (0); 1639df8bae1dSRodney W. Grimes } 1640df8bae1dSRodney W. Grimes 1641c9bf0111SKATO Takenori static int 1642df8bae1dSRodney W. Grimes union_islocked(ap) 1643df8bae1dSRodney W. Grimes struct vop_islocked_args /* { 1644df8bae1dSRodney W. Grimes struct vnode *a_vp; 1645df8bae1dSRodney W. Grimes } */ *ap; 1646df8bae1dSRodney W. Grimes { 1647df8bae1dSRodney W. Grimes 1648df8bae1dSRodney W. Grimes return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0); 1649df8bae1dSRodney W. Grimes } 1650df8bae1dSRodney W. Grimes 1651c9bf0111SKATO Takenori static int 1652df8bae1dSRodney W. Grimes union_pathconf(ap) 1653df8bae1dSRodney W. Grimes struct vop_pathconf_args /* { 1654df8bae1dSRodney W. Grimes struct vnode *a_vp; 1655df8bae1dSRodney W. Grimes int a_name; 1656df8bae1dSRodney W. Grimes int *a_retval; 1657df8bae1dSRodney W. Grimes } */ *ap; 1658df8bae1dSRodney W. Grimes { 1659df8bae1dSRodney W. Grimes int error; 1660996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1661df8bae1dSRodney W. Grimes struct vnode *vp = OTHERVP(ap->a_vp); 1662df8bae1dSRodney W. Grimes int dolock = (vp == LOWERVP(ap->a_vp)); 1663df8bae1dSRodney W. Grimes 1664df8bae1dSRodney W. Grimes if (dolock) 1665996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1666df8bae1dSRodney W. Grimes else 1667996c772fSJohn Dyson FIXUP(VTOUNION(ap->a_vp), p); 1668996c772fSJohn Dyson ap->a_vp = vp; 1669996c772fSJohn Dyson error = VCALL(vp, VOFFSET(vop_pathconf), ap); 1670df8bae1dSRodney W. Grimes if (dolock) 1671996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1672df8bae1dSRodney W. Grimes 1673df8bae1dSRodney W. Grimes return (error); 1674df8bae1dSRodney W. Grimes } 1675df8bae1dSRodney W. Grimes 1676c9bf0111SKATO Takenori static int 1677df8bae1dSRodney W. Grimes union_advlock(ap) 1678df8bae1dSRodney W. Grimes struct vop_advlock_args /* { 1679df8bae1dSRodney W. Grimes struct vnode *a_vp; 1680df8bae1dSRodney W. Grimes caddr_t a_id; 1681df8bae1dSRodney W. Grimes int a_op; 1682df8bae1dSRodney W. Grimes struct flock *a_fl; 1683df8bae1dSRodney W. Grimes int a_flags; 1684df8bae1dSRodney W. Grimes } */ *ap; 1685df8bae1dSRodney W. Grimes { 1686996c772fSJohn Dyson register struct vnode *ovp = OTHERVP(ap->a_vp); 1687df8bae1dSRodney W. Grimes 1688996c772fSJohn Dyson ap->a_vp = ovp; 1689996c772fSJohn Dyson return (VCALL(ovp, VOFFSET(vop_advlock), ap)); 1690df8bae1dSRodney W. Grimes } 1691df8bae1dSRodney W. Grimes 1692df8bae1dSRodney W. Grimes 1693df8bae1dSRodney W. Grimes /* 1694df8bae1dSRodney W. Grimes * XXX - vop_strategy must be hand coded because it has no 1695df8bae1dSRodney W. Grimes * vnode in its arguments. 1696df8bae1dSRodney W. Grimes * This goes away with a merged VM/buffer cache. 1697df8bae1dSRodney W. Grimes */ 1698c9bf0111SKATO Takenori static int 1699df8bae1dSRodney W. Grimes union_strategy(ap) 1700df8bae1dSRodney W. Grimes struct vop_strategy_args /* { 1701df8bae1dSRodney W. Grimes struct buf *a_bp; 1702df8bae1dSRodney W. Grimes } */ *ap; 1703df8bae1dSRodney W. Grimes { 1704df8bae1dSRodney W. Grimes struct buf *bp = ap->a_bp; 1705df8bae1dSRodney W. Grimes int error; 1706df8bae1dSRodney W. Grimes struct vnode *savedvp; 1707df8bae1dSRodney W. Grimes 1708df8bae1dSRodney W. Grimes savedvp = bp->b_vp; 1709df8bae1dSRodney W. Grimes bp->b_vp = OTHERVP(bp->b_vp); 1710df8bae1dSRodney W. Grimes 1711df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 1712df8bae1dSRodney W. Grimes if (bp->b_vp == NULLVP) 1713df8bae1dSRodney W. Grimes panic("union_strategy: nil vp"); 1714df8bae1dSRodney W. Grimes if (((bp->b_flags & B_READ) == 0) && 1715df8bae1dSRodney W. Grimes (bp->b_vp == LOWERVP(savedvp))) 1716df8bae1dSRodney W. Grimes panic("union_strategy: writing to lowervp"); 1717df8bae1dSRodney W. Grimes #endif 1718df8bae1dSRodney W. Grimes 1719df8bae1dSRodney W. Grimes error = VOP_STRATEGY(bp); 1720df8bae1dSRodney W. Grimes bp->b_vp = savedvp; 1721df8bae1dSRodney W. Grimes 1722df8bae1dSRodney W. Grimes return (error); 1723df8bae1dSRodney W. Grimes } 1724df8bae1dSRodney W. Grimes 1725df8bae1dSRodney W. Grimes /* 1726df8bae1dSRodney W. Grimes * Global vfs data structures 1727df8bae1dSRodney W. Grimes */ 1728f57e6547SBruce Evans vop_t **union_vnodeop_p; 1729df8bae1dSRodney W. Grimes struct vnodeopv_entry_desc union_vnodeop_entries[] = { 1730f57e6547SBruce Evans { &vop_default_desc, (vop_t *)vn_default_error }, 1731f57e6547SBruce Evans { &vop_lookup_desc, (vop_t *)union_lookup }, /* lookup */ 1732f57e6547SBruce Evans { &vop_create_desc, (vop_t *)union_create }, /* create */ 1733996c772fSJohn Dyson { &vop_whiteout_desc, (vop_t *)union_whiteout }, /* whiteout */ 1734f57e6547SBruce Evans { &vop_mknod_desc, (vop_t *)union_mknod }, /* mknod */ 1735f57e6547SBruce Evans { &vop_open_desc, (vop_t *)union_open }, /* open */ 1736f57e6547SBruce Evans { &vop_close_desc, (vop_t *)union_close }, /* close */ 1737f57e6547SBruce Evans { &vop_access_desc, (vop_t *)union_access }, /* access */ 1738f57e6547SBruce Evans { &vop_getattr_desc, (vop_t *)union_getattr }, /* getattr */ 1739f57e6547SBruce Evans { &vop_setattr_desc, (vop_t *)union_setattr }, /* setattr */ 1740f57e6547SBruce Evans { &vop_read_desc, (vop_t *)union_read }, /* read */ 1741f57e6547SBruce Evans { &vop_write_desc, (vop_t *)union_write }, /* write */ 1742996c772fSJohn Dyson { &vop_lease_desc, (vop_t *)union_lease }, /* lease */ 1743f57e6547SBruce Evans { &vop_ioctl_desc, (vop_t *)union_ioctl }, /* ioctl */ 1744f57e6547SBruce Evans { &vop_select_desc, (vop_t *)union_select }, /* select */ 1745996c772fSJohn Dyson { &vop_revoke_desc, (vop_t *)union_revoke }, /* revoke */ 1746f57e6547SBruce Evans { &vop_mmap_desc, (vop_t *)union_mmap }, /* mmap */ 1747f57e6547SBruce Evans { &vop_fsync_desc, (vop_t *)union_fsync }, /* fsync */ 1748f57e6547SBruce Evans { &vop_seek_desc, (vop_t *)union_seek }, /* seek */ 1749f57e6547SBruce Evans { &vop_remove_desc, (vop_t *)union_remove }, /* remove */ 1750f57e6547SBruce Evans { &vop_link_desc, (vop_t *)union_link }, /* link */ 1751f57e6547SBruce Evans { &vop_rename_desc, (vop_t *)union_rename }, /* rename */ 1752f57e6547SBruce Evans { &vop_mkdir_desc, (vop_t *)union_mkdir }, /* mkdir */ 1753f57e6547SBruce Evans { &vop_rmdir_desc, (vop_t *)union_rmdir }, /* rmdir */ 1754f57e6547SBruce Evans { &vop_symlink_desc, (vop_t *)union_symlink }, /* symlink */ 1755f57e6547SBruce Evans { &vop_readdir_desc, (vop_t *)union_readdir }, /* readdir */ 1756f57e6547SBruce Evans { &vop_readlink_desc, (vop_t *)union_readlink }, /* readlink */ 1757f57e6547SBruce Evans { &vop_abortop_desc, (vop_t *)union_abortop }, /* abortop */ 1758f57e6547SBruce Evans { &vop_inactive_desc, (vop_t *)union_inactive }, /* inactive */ 1759f57e6547SBruce Evans { &vop_reclaim_desc, (vop_t *)union_reclaim }, /* reclaim */ 1760f57e6547SBruce Evans { &vop_lock_desc, (vop_t *)union_lock }, /* lock */ 1761f57e6547SBruce Evans { &vop_unlock_desc, (vop_t *)union_unlock }, /* unlock */ 1762f57e6547SBruce Evans { &vop_bmap_desc, (vop_t *)union_bmap }, /* bmap */ 1763f57e6547SBruce Evans { &vop_strategy_desc, (vop_t *)union_strategy }, /* strategy */ 1764f57e6547SBruce Evans { &vop_print_desc, (vop_t *)union_print }, /* print */ 1765f57e6547SBruce Evans { &vop_islocked_desc, (vop_t *)union_islocked }, /* islocked */ 1766f57e6547SBruce Evans { &vop_pathconf_desc, (vop_t *)union_pathconf }, /* pathconf */ 1767f57e6547SBruce Evans { &vop_advlock_desc, (vop_t *)union_advlock }, /* advlock */ 1768df8bae1dSRodney W. Grimes #ifdef notdef 1769f57e6547SBruce Evans { &vop_blkatoff_desc, (vop_t *)union_blkatoff }, /* blkatoff */ 1770f57e6547SBruce Evans { &vop_valloc_desc, (vop_t *)union_valloc }, /* valloc */ 1771f57e6547SBruce Evans { &vop_vfree_desc, (vop_t *)union_vfree }, /* vfree */ 1772f57e6547SBruce Evans { &vop_truncate_desc, (vop_t *)union_truncate }, /* truncate */ 1773f57e6547SBruce Evans { &vop_update_desc, (vop_t *)union_update }, /* update */ 1774f57e6547SBruce Evans { &vop_bwrite_desc, (vop_t *)union_bwrite }, /* bwrite */ 1775df8bae1dSRodney W. Grimes #endif 1776f57e6547SBruce Evans { NULL, NULL } 1777df8bae1dSRodney W. Grimes }; 1778df8bae1dSRodney W. Grimes struct vnodeopv_desc union_vnodeop_opv_desc = 1779df8bae1dSRodney W. Grimes { &union_vnodeop_p, union_vnodeop_entries }; 1780c901836cSGarrett Wollman 1781c901836cSGarrett Wollman VNODEOP_SET(union_vnodeop_opv_desc); 1782