165934Spendry /* 265934Spendry * Copyright (c) 1994 Jan-Simon Pendry 365934Spendry * Copyright (c) 1994 465934Spendry * The Regents of the University of California. All rights reserved. 565934Spendry * 665934Spendry * This code is derived from software contributed to Berkeley by 765934Spendry * Jan-Simon Pendry. 865934Spendry * 965934Spendry * %sccs.include.redist.c% 1065934Spendry * 11*66051Spendry * @(#)union_subr.c 2.1 (Berkeley) 02/10/94 1265934Spendry */ 1365934Spendry 1465934Spendry #include <sys/param.h> 1565934Spendry #include <sys/systm.h> 1665934Spendry #include <sys/time.h> 1765934Spendry #include <sys/kernel.h> 1865934Spendry #include <sys/vnode.h> 1965934Spendry #include <sys/namei.h> 2065934Spendry #include <sys/malloc.h> 2165994Spendry #include <sys/file.h> 2265997Spendry #include <sys/filedesc.h> 2365934Spendry #include "union.h" /*<miscfs/union/union.h>*/ 2465934Spendry 2565992Spendry #ifdef DIAGNOSTIC 2665992Spendry #include <sys/proc.h> 2765992Spendry #endif 2865992Spendry 2965934Spendry static struct union_node *unhead; 3065934Spendry static int unvplock; 3165934Spendry 3265934Spendry int 3365934Spendry union_init() 3465934Spendry { 3565934Spendry 3665934Spendry unhead = 0; 3765934Spendry unvplock = 0; 3865934Spendry } 3965934Spendry 40*66051Spendry static void 41*66051Spendry union_remlist(un) 42*66051Spendry struct union_node *un; 43*66051Spendry { 44*66051Spendry struct union_node **unpp; 45*66051Spendry 46*66051Spendry for (unpp = &unhead; *unpp != 0; unpp = &(*unpp)->un_next) { 47*66051Spendry if (*unpp == un) { 48*66051Spendry *unpp = un->un_next; 49*66051Spendry break; 50*66051Spendry } 51*66051Spendry } 52*66051Spendry } 53*66051Spendry 5465934Spendry /* 5565934Spendry * allocate a union_node/vnode pair. the vnode is 5665965Spendry * referenced and locked. the new vnode is returned 5765965Spendry * via (vpp). (mp) is the mountpoint of the union filesystem, 5865965Spendry * (dvp) is the parent directory where the upper layer object 5965965Spendry * should exist (but doesn't) and (cnp) is the componentname 6065965Spendry * information which is partially copied to allow the upper 6165965Spendry * layer object to be created at a later time. (uppervp) 6265965Spendry * and (lowervp) reference the upper and lower layer objects 6365965Spendry * being mapped. either, but not both, can be nil. 64*66051Spendry * if supplied, (uppervp) is locked. 6565997Spendry * the reference is either maintained in the new union_node 6665997Spendry * object which is allocated, or they are vrele'd. 6765934Spendry * 6865934Spendry * all union_nodes are maintained on a singly-linked 6965934Spendry * list. new nodes are only allocated when they cannot 7065934Spendry * be found on this list. entries on the list are 7165934Spendry * removed when the vfs reclaim entry is called. 7265934Spendry * 7365934Spendry * a single lock is kept for the entire list. this is 7465934Spendry * needed because the getnewvnode() function can block 7565934Spendry * waiting for a vnode to become free, in which case there 7665934Spendry * may be more than one process trying to get the same 7765934Spendry * vnode. this lock is only taken if we are going to 7865934Spendry * call getnewvnode, since the kernel itself is single-threaded. 7965934Spendry * 8065934Spendry * if an entry is found on the list, then call vget() to 8165934Spendry * take a reference. this is done because there may be 8265934Spendry * zero references to it and so it needs to removed from 8365934Spendry * the vnode free list. 8465934Spendry */ 8565934Spendry int 8665992Spendry union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) 8765934Spendry struct vnode **vpp; 8865934Spendry struct mount *mp; 8965992Spendry struct vnode *undvp; 9065934Spendry struct vnode *dvp; /* may be null */ 9165934Spendry struct componentname *cnp; /* may be null */ 9265934Spendry struct vnode *uppervp; /* may be null */ 9365934Spendry struct vnode *lowervp; /* may be null */ 9465934Spendry { 9565934Spendry int error; 9665934Spendry struct union_node *un; 9765934Spendry struct union_node **pp; 9865965Spendry struct vnode *xlowervp = 0; 9965934Spendry 10065965Spendry if (uppervp == 0 && lowervp == 0) 10165965Spendry panic("union: unidentifiable allocation"); 10265965Spendry 10365965Spendry if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { 10465965Spendry xlowervp = lowervp; 10565965Spendry lowervp = 0; 10665965Spendry } 10765965Spendry 10865934Spendry loop: 10965934Spendry for (un = unhead; un != 0; un = un->un_next) { 11065934Spendry if ((un->un_lowervp == lowervp || 11165934Spendry un->un_lowervp == 0) && 11265934Spendry (un->un_uppervp == uppervp || 11365934Spendry un->un_uppervp == 0) && 11465934Spendry (UNIONTOV(un)->v_mount == mp)) { 11565992Spendry if (vget(UNIONTOV(un), 0)) 11665934Spendry goto loop; 117*66051Spendry break; 118*66051Spendry } 119*66051Spendry } 12066027Spendry 121*66051Spendry if (un) { 122*66051Spendry /* 123*66051Spendry * Obtain a lock on the union_node. 124*66051Spendry * uppervp is locked, though un->un_uppervp 125*66051Spendry * may not be. this doesn't break the locking 126*66051Spendry * hierarchy since in the case that un->un_uppervp 127*66051Spendry * is not yet locked it will be vrele'd and replaced 128*66051Spendry * with uppervp. 129*66051Spendry */ 130*66051Spendry 131*66051Spendry if ((dvp != NULLVP) && (uppervp == dvp)) { 13266027Spendry /* 133*66051Spendry * Access ``.'', so (un) will already 134*66051Spendry * be locked. Since this process has 135*66051Spendry * the lock on (uppervp) no other 136*66051Spendry * process can hold the lock on (un). 13766027Spendry */ 138*66051Spendry #ifdef DIAGNOSTIC 139*66051Spendry if ((un->un_flags & UN_LOCKED) == 0) 140*66051Spendry panic("union: . not locked"); 141*66051Spendry else if (curproc && un->un_pid != curproc->p_pid && 142*66051Spendry un->un_pid > -1 && curproc->p_pid > -1) 143*66051Spendry panic("union: allocvp not lock owner"); 144*66051Spendry #endif 145*66051Spendry } else { 146*66051Spendry if (un->un_flags & UN_LOCKED) { 147*66051Spendry vrele(UNIONTOV(un)); 148*66051Spendry un->un_flags |= UN_WANT; 149*66051Spendry sleep((caddr_t) &un->un_flags, PINOD); 150*66051Spendry goto loop; 15165992Spendry } 152*66051Spendry un->un_flags |= UN_LOCKED; 15366027Spendry 154*66051Spendry #ifdef DIAGNOSTIC 155*66051Spendry if (curproc) 156*66051Spendry un->un_pid = curproc->p_pid; 157*66051Spendry else 158*66051Spendry un->un_pid = -1; 159*66051Spendry #endif 160*66051Spendry } 161*66051Spendry 162*66051Spendry /* 163*66051Spendry * At this point, the union_node is locked, 164*66051Spendry * un->un_uppervp may not be locked, and uppervp 165*66051Spendry * is locked or nil. 166*66051Spendry */ 167*66051Spendry 168*66051Spendry /* 169*66051Spendry * Save information about the upper layer. 170*66051Spendry */ 171*66051Spendry if (uppervp != un->un_uppervp) { 172*66051Spendry if (un->un_uppervp) 173*66051Spendry vrele(un->un_uppervp); 174*66051Spendry un->un_uppervp = uppervp; 175*66051Spendry } else if (uppervp) { 176*66051Spendry vrele(uppervp); 177*66051Spendry } 178*66051Spendry 179*66051Spendry if (un->un_uppervp) { 180*66051Spendry un->un_flags |= UN_ULOCK; 181*66051Spendry un->un_flags &= ~UN_KLOCK; 182*66051Spendry } 183*66051Spendry 184*66051Spendry /* 185*66051Spendry * Save information about the lower layer. 186*66051Spendry * This needs to keep track of pathname 187*66051Spendry * and directory information which union_vn_create 188*66051Spendry * might need. 189*66051Spendry */ 190*66051Spendry if (lowervp != un->un_lowervp) { 191*66051Spendry if (un->un_lowervp) { 192*66051Spendry vrele(un->un_lowervp); 193*66051Spendry free(un->un_path, M_TEMP); 194*66051Spendry vrele(un->un_dirvp); 19565992Spendry } 196*66051Spendry un->un_lowervp = lowervp; 197*66051Spendry if (cnp && (lowervp != NULLVP) && 198*66051Spendry (lowervp->v_type == VREG)) { 199*66051Spendry un->un_hash = cnp->cn_hash; 200*66051Spendry un->un_path = malloc(cnp->cn_namelen+1, 201*66051Spendry M_TEMP, M_WAITOK); 202*66051Spendry bcopy(cnp->cn_nameptr, un->un_path, 203*66051Spendry cnp->cn_namelen); 204*66051Spendry un->un_path[cnp->cn_namelen] = '\0'; 205*66051Spendry VREF(dvp); 206*66051Spendry un->un_dirvp = dvp; 207*66051Spendry } 208*66051Spendry } else if (lowervp) { 209*66051Spendry vrele(lowervp); 21065934Spendry } 211*66051Spendry *vpp = UNIONTOV(un); 212*66051Spendry return (0); 21365934Spendry } 21465934Spendry 21565934Spendry /* 21665934Spendry * otherwise lock the vp list while we call getnewvnode 21765934Spendry * since that can block. 21865934Spendry */ 21965934Spendry if (unvplock & UN_LOCKED) { 22065934Spendry unvplock |= UN_WANT; 22165934Spendry sleep((caddr_t) &unvplock, PINOD); 22265934Spendry goto loop; 22365934Spendry } 22465934Spendry unvplock |= UN_LOCKED; 22565934Spendry 22665934Spendry error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); 227*66051Spendry if (error) { 228*66051Spendry if (uppervp) { 229*66051Spendry if (dvp == uppervp) 230*66051Spendry vrele(uppervp); 231*66051Spendry else 232*66051Spendry vput(uppervp); 233*66051Spendry } 234*66051Spendry if (lowervp) 235*66051Spendry vrele(lowervp); 236*66051Spendry 23765934Spendry goto out; 238*66051Spendry } 23965934Spendry 24065934Spendry MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), 24165934Spendry M_TEMP, M_WAITOK); 24265934Spendry 24365965Spendry if (uppervp) 24465965Spendry (*vpp)->v_type = uppervp->v_type; 24565965Spendry else 24665965Spendry (*vpp)->v_type = lowervp->v_type; 24765934Spendry un = VTOUNION(*vpp); 24865992Spendry un->un_vnode = *vpp; 24965934Spendry un->un_next = 0; 25065934Spendry un->un_uppervp = uppervp; 25165934Spendry un->un_lowervp = lowervp; 25266028Spendry un->un_openl = 0; 253*66051Spendry un->un_flags = UN_LOCKED; 254*66051Spendry if (un->un_uppervp) 255*66051Spendry un->un_flags |= UN_ULOCK; 256*66051Spendry #ifdef DIAGNOSTIC 257*66051Spendry if (curproc) 258*66051Spendry un->un_pid = curproc->p_pid; 259*66051Spendry else 260*66051Spendry un->un_pid = -1; 261*66051Spendry #endif 26266027Spendry if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) { 26366027Spendry un->un_hash = cnp->cn_hash; 26465934Spendry un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); 26565934Spendry bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); 26665934Spendry un->un_path[cnp->cn_namelen] = '\0'; 26765965Spendry VREF(dvp); 26865965Spendry un->un_dirvp = dvp; 26965934Spendry } else { 27066027Spendry un->un_hash = 0; 27165934Spendry un->un_path = 0; 27265965Spendry un->un_dirvp = 0; 27365934Spendry } 27465934Spendry 27565934Spendry /* add to union vnode list */ 27665934Spendry for (pp = &unhead; *pp; pp = &(*pp)->un_next) 27765934Spendry continue; 27865934Spendry *pp = un; 27965934Spendry 28065965Spendry if (xlowervp) 28165965Spendry vrele(xlowervp); 28265965Spendry 28365934Spendry out: 28465934Spendry unvplock &= ~UN_LOCKED; 28565934Spendry 28665934Spendry if (unvplock & UN_WANT) { 28765934Spendry unvplock &= ~UN_WANT; 28865934Spendry wakeup((caddr_t) &unvplock); 28965934Spendry } 29065934Spendry 29165934Spendry return (error); 29265934Spendry } 29365934Spendry 29465934Spendry int 29565934Spendry union_freevp(vp) 29665934Spendry struct vnode *vp; 29765934Spendry { 29865934Spendry struct union_node *un = VTOUNION(vp); 29965934Spendry 300*66051Spendry union_remlist(un); 30165934Spendry 30265934Spendry FREE(vp->v_data, M_TEMP); 30365934Spendry vp->v_data = 0; 30465934Spendry return (0); 30565934Spendry } 30665994Spendry 30765994Spendry /* 30865994Spendry * copyfile. copy the vnode (fvp) to the vnode (tvp) 30965994Spendry * using a sequence of reads and writes. both (fvp) 31065994Spendry * and (tvp) are locked on entry and exit. 31165994Spendry */ 31265994Spendry int 31365994Spendry union_copyfile(p, cred, fvp, tvp) 31465994Spendry struct proc *p; 31565994Spendry struct ucred *cred; 31665994Spendry struct vnode *fvp; 31765994Spendry struct vnode *tvp; 31865994Spendry { 31965994Spendry char *buf; 32065994Spendry struct uio uio; 32165994Spendry struct iovec iov; 32265994Spendry int error = 0; 32365994Spendry 32465994Spendry /* 32565994Spendry * strategy: 32665994Spendry * allocate a buffer of size MAXBSIZE. 32765994Spendry * loop doing reads and writes, keeping track 32865994Spendry * of the current uio offset. 32965994Spendry * give up at the first sign of trouble. 33065994Spendry */ 33165994Spendry 33265994Spendry uio.uio_procp = p; 33365994Spendry uio.uio_segflg = UIO_SYSSPACE; 33465994Spendry uio.uio_offset = 0; 33565994Spendry 33665994Spendry VOP_UNLOCK(fvp); /* XXX */ 33765994Spendry LEASE_CHECK(fvp, p, cred, LEASE_READ); 33865994Spendry VOP_LOCK(fvp); /* XXX */ 33965994Spendry VOP_UNLOCK(tvp); /* XXX */ 34065994Spendry LEASE_CHECK(tvp, p, cred, LEASE_WRITE); 34165994Spendry VOP_LOCK(tvp); /* XXX */ 34265994Spendry 34365994Spendry buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); 34465994Spendry 34565994Spendry /* ugly loop follows... */ 34665994Spendry do { 34765994Spendry off_t offset = uio.uio_offset; 34865994Spendry 34965994Spendry uio.uio_iov = &iov; 35065994Spendry uio.uio_iovcnt = 1; 35165994Spendry iov.iov_base = buf; 35265994Spendry iov.iov_len = MAXBSIZE; 35365994Spendry uio.uio_resid = iov.iov_len; 35465994Spendry uio.uio_rw = UIO_READ; 35565994Spendry error = VOP_READ(fvp, &uio, 0, cred); 35665994Spendry 35765994Spendry if (error == 0) { 35865994Spendry uio.uio_iov = &iov; 35965994Spendry uio.uio_iovcnt = 1; 36065994Spendry iov.iov_base = buf; 36165994Spendry iov.iov_len = MAXBSIZE - uio.uio_resid; 36265994Spendry uio.uio_offset = offset; 36365994Spendry uio.uio_rw = UIO_WRITE; 36465994Spendry uio.uio_resid = iov.iov_len; 36565994Spendry 36665994Spendry if (uio.uio_resid == 0) 36765994Spendry break; 36865994Spendry 36965994Spendry do { 37065994Spendry error = VOP_WRITE(tvp, &uio, 0, cred); 37165994Spendry } while ((uio.uio_resid > 0) && (error == 0)); 37265994Spendry } 37365994Spendry 37465994Spendry } while (error == 0); 37565994Spendry 37665994Spendry free(buf, M_TEMP); 37765994Spendry return (error); 37865994Spendry } 37965994Spendry 38065994Spendry /* 38165997Spendry * Create a shadow directory in the upper layer. 38265997Spendry * The new vnode is returned locked. 38365997Spendry * 38465997Spendry * (um) points to the union mount structure for access to the 38565997Spendry * the mounting process's credentials. 38665997Spendry * (dvp) is the directory in which to create the shadow directory. 38765997Spendry * it is unlocked on entry and exit. 38865997Spendry * (cnp) is the componentname to be created. 38965997Spendry * (vpp) is the returned newly created shadow directory, which 39065997Spendry * is returned locked. 39165997Spendry */ 39265997Spendry int 39365997Spendry union_mkshadow(um, dvp, cnp, vpp) 39465997Spendry struct union_mount *um; 39565997Spendry struct vnode *dvp; 39665997Spendry struct componentname *cnp; 39765997Spendry struct vnode **vpp; 39865997Spendry { 39965997Spendry int error; 40065997Spendry struct vattr va; 40165997Spendry struct proc *p = cnp->cn_proc; 40265997Spendry struct componentname cn; 40365997Spendry 40465997Spendry /* 40565997Spendry * policy: when creating the shadow directory in the 40666034Spendry * upper layer, create it owned by the user who did 40766034Spendry * the mount, group from parent directory, and mode 40866034Spendry * 777 modified by umask (ie mostly identical to the 40966034Spendry * mkdir syscall). (jsp, kb) 41065997Spendry */ 41165997Spendry 41265997Spendry /* 41365997Spendry * A new componentname structure must be faked up because 41465997Spendry * there is no way to know where the upper level cnp came 41565997Spendry * from or what it is being used for. This must duplicate 41665997Spendry * some of the work done by NDINIT, some of the work done 41765997Spendry * by namei, some of the work done by lookup and some of 41865997Spendry * the work done by VOP_LOOKUP when given a CREATE flag. 41965997Spendry * Conclusion: Horrible. 42065997Spendry * 42165997Spendry * The pathname buffer will be FREEed by VOP_MKDIR. 42265997Spendry */ 42365997Spendry cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK); 42466027Spendry bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen); 42566027Spendry cn.cn_pnbuf[cnp->cn_namelen] = '\0'; 42665997Spendry 42765997Spendry cn.cn_nameiop = CREATE; 42865997Spendry cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|ISLASTCN); 42965997Spendry cn.cn_proc = cnp->cn_proc; 43066034Spendry cn.cn_cred = um->um_cred; 43165997Spendry cn.cn_nameptr = cn.cn_pnbuf; 43265997Spendry cn.cn_namelen = cnp->cn_namelen; 43365997Spendry cn.cn_hash = cnp->cn_hash; 43465997Spendry cn.cn_consume = cnp->cn_consume; 43565997Spendry 43666027Spendry VREF(dvp); 43765997Spendry if (error = relookup(dvp, vpp, &cn)) 43865997Spendry return (error); 43966027Spendry vrele(dvp); 44065997Spendry 44165997Spendry if (*vpp) { 44265997Spendry VOP_ABORTOP(dvp, &cn); 44365997Spendry VOP_UNLOCK(dvp); 44465997Spendry vrele(*vpp); 44565997Spendry *vpp = NULLVP; 44665997Spendry return (EEXIST); 44765997Spendry } 44865997Spendry 44965997Spendry VATTR_NULL(&va); 45065997Spendry va.va_type = VDIR; 45166034Spendry va.va_mode = um->um_cmode; 45265997Spendry 45365997Spendry /* LEASE_CHECK: dvp is locked */ 45465997Spendry LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE); 45565997Spendry 45665997Spendry VREF(dvp); 45765997Spendry error = VOP_MKDIR(dvp, vpp, &cn, &va); 45865997Spendry return (error); 45965997Spendry } 46065997Spendry 46165997Spendry /* 46265994Spendry * union_vn_create: creates and opens a new shadow file 46365994Spendry * on the upper union layer. this function is similar 46465994Spendry * in spirit to calling vn_open but it avoids calling namei(). 46565994Spendry * the problem with calling namei is that a) it locks too many 46665994Spendry * things, and b) it doesn't start at the "right" directory, 46765994Spendry * whereas relookup is told where to start. 46865994Spendry */ 46965994Spendry int 47065997Spendry union_vn_create(vpp, un, p) 47165994Spendry struct vnode **vpp; 47265994Spendry struct union_node *un; 47365994Spendry struct proc *p; 47465994Spendry { 47565994Spendry struct vnode *vp; 47665994Spendry struct ucred *cred = p->p_ucred; 47765994Spendry struct vattr vat; 47865994Spendry struct vattr *vap = &vat; 47965994Spendry int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL); 48065994Spendry int error; 48166027Spendry int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask; 48265994Spendry char *cp; 48365994Spendry struct componentname cn; 48465994Spendry 48565994Spendry *vpp = NULLVP; 48665994Spendry 48766034Spendry /* 48866034Spendry * Build a new componentname structure (for the same 48966034Spendry * reasons outlines in union_mkshadow). 49066034Spendry * The difference here is that the file is owned by 49166034Spendry * the current user, rather than by the person who 49266034Spendry * did the mount, since the current user needs to be 49366034Spendry * able to write the file (that's why it is being 49466034Spendry * copied in the first place). 49566034Spendry */ 49665994Spendry cn.cn_namelen = strlen(un->un_path); 49765994Spendry cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen, M_NAMEI, M_WAITOK); 49865994Spendry bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1); 49965994Spendry cn.cn_nameiop = CREATE; 50065994Spendry cn.cn_flags = (LOCKLEAF|LOCKPARENT|HASBUF|SAVENAME|ISLASTCN); 50165994Spendry cn.cn_proc = p; 50265994Spendry cn.cn_cred = p->p_ucred; 50365994Spendry cn.cn_nameptr = cn.cn_pnbuf; 50466027Spendry cn.cn_hash = un->un_hash; 50565994Spendry cn.cn_consume = 0; 50665994Spendry 50766027Spendry VREF(un->un_dirvp); 50865994Spendry if (error = relookup(un->un_dirvp, &vp, &cn)) 50965994Spendry return (error); 51066027Spendry vrele(un->un_dirvp); 51166027Spendry 51265994Spendry if (vp == NULLVP) { 51366034Spendry /* 51466034Spendry * Good - there was no race to create the file 51566034Spendry * so go ahead and create it. The permissions 51666034Spendry * on the file will be 0666 modified by the 51766034Spendry * current user's umask. Access to the file, while 51866034Spendry * it is unioned, will require access to the top *and* 51966034Spendry * bottom files. Access when not unioned will simply 52066034Spendry * require access to the top-level file. 52166034Spendry * TODO: confirm choice of access permissions. 52266034Spendry */ 52365994Spendry VATTR_NULL(vap); 52465994Spendry vap->va_type = VREG; 52565994Spendry vap->va_mode = cmode; 52665994Spendry LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE); 52765994Spendry if (error = VOP_CREATE(un->un_dirvp, &vp, 52865994Spendry &cn, vap)) 52965994Spendry return (error); 53065994Spendry } else { 53165994Spendry VOP_ABORTOP(un->un_dirvp, &cn); 53265994Spendry if (un->un_dirvp == vp) 53365994Spendry vrele(un->un_dirvp); 53465994Spendry else 53565994Spendry vput(vp); 53665994Spendry error = EEXIST; 53765994Spendry goto bad; 53865994Spendry } 53965994Spendry 54065994Spendry if (vp->v_type != VREG) { 54165994Spendry error = EOPNOTSUPP; 54265994Spendry goto bad; 54365994Spendry } 54465994Spendry 54565994Spendry VOP_UNLOCK(vp); /* XXX */ 54665994Spendry LEASE_CHECK(vp, p, cred, LEASE_WRITE); 54765994Spendry VOP_LOCK(vp); /* XXX */ 54865994Spendry VATTR_NULL(vap); 54965994Spendry vap->va_size = 0; 55065994Spendry if (error = VOP_SETATTR(vp, vap, cred, p)) 55165994Spendry goto bad; 55265994Spendry 55365994Spendry if (error = VOP_OPEN(vp, fmode, cred, p)) 55465994Spendry goto bad; 55565994Spendry 55665994Spendry vp->v_writecount++; 55765994Spendry *vpp = vp; 55865994Spendry return (0); 55965994Spendry bad: 56065994Spendry vput(vp); 56165994Spendry return (error); 56265994Spendry } 56366027Spendry 56466027Spendry int 56566028Spendry union_vn_close(vp, fmode, cred, p) 56666027Spendry struct vnode *vp; 56766027Spendry int fmode; 56866028Spendry struct ucred *cred; 56966028Spendry struct proc *p; 57066027Spendry { 57166027Spendry if (fmode & FWRITE) 57266027Spendry --vp->v_writecount; 57366027Spendry return (VOP_CLOSE(vp, fmode)); 57466027Spendry } 57566027Spendry 57666027Spendry void 57766027Spendry union_removed_upper(un) 57866027Spendry struct union_node *un; 57966027Spendry { 580*66051Spendry if (un->un_flags & UN_ULOCK) { 581*66051Spendry un->un_flags &= ~UN_ULOCK; 582*66051Spendry vput(un->un_uppervp); 583*66051Spendry } else { 584*66051Spendry vrele(un->un_uppervp); 585*66051Spendry } 58666027Spendry un->un_uppervp = NULLVP; 58766027Spendry } 58866028Spendry 58966028Spendry struct vnode * 59066028Spendry union_lowervp(vp) 59166028Spendry struct vnode *vp; 59266028Spendry { 59366028Spendry struct union_node *un = VTOUNION(vp); 59466028Spendry 59566028Spendry if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) { 59666028Spendry if (vget(un->un_lowervp, 0)) 59766028Spendry return (NULLVP); 59866028Spendry } 59966028Spendry 60066028Spendry return (un->un_lowervp); 60166028Spendry } 602