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*66060Spendry * @(#)union_subr.c 8.3 (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> 2366053Spendry #include <sys/queue.h> 2466055Spendry #include <miscfs/union/union.h> 2565934Spendry 2665992Spendry #ifdef DIAGNOSTIC 2765992Spendry #include <sys/proc.h> 2865992Spendry #endif 2965992Spendry 3066053Spendry /* must be power of two, otherwise change UNION_HASH() */ 3166053Spendry #define NHASH 32 3265934Spendry 3366053Spendry /* unsigned int ... */ 3466053Spendry #define UNION_HASH(u, l) \ 3566053Spendry (((((unsigned long) (u)) + ((unsigned long) l)) >> 8) & (NHASH-1)) 3666053Spendry 3766053Spendry static LIST_HEAD(unhead, union_node) unhead[NHASH]; 3866053Spendry static int unvplock[NHASH]; 3966053Spendry 4065934Spendry int 4165934Spendry union_init() 4265934Spendry { 4366053Spendry int i; 4465934Spendry 4566053Spendry for (i = 0; i < NHASH; i++) 4666053Spendry LIST_INIT(&unhead[i]); 4766053Spendry bzero((caddr_t) unvplock, sizeof(unvplock)); 4865934Spendry } 4965934Spendry 5066053Spendry static int 5166053Spendry union_list_lock(ix) 5266053Spendry int ix; 5366053Spendry { 5466053Spendry 5566053Spendry if (unvplock[ix] & UN_LOCKED) { 5666053Spendry unvplock[ix] |= UN_WANT; 5766053Spendry sleep((caddr_t) &unvplock[ix], PINOD); 5866053Spendry return (1); 5966053Spendry } 6066053Spendry 6166053Spendry unvplock[ix] |= UN_LOCKED; 6266053Spendry 6366053Spendry return (0); 6466053Spendry } 6566053Spendry 6666051Spendry static void 6766053Spendry union_list_unlock(ix) 6866053Spendry int ix; 6966053Spendry { 7066053Spendry 7166053Spendry unvplock[ix] &= ~UN_LOCKED; 7266053Spendry 7366053Spendry if (unvplock[ix] & UN_WANT) { 7466053Spendry unvplock[ix] &= ~UN_WANT; 7566053Spendry wakeup((caddr_t) &unvplock[ix]); 7666053Spendry } 7766053Spendry } 7866053Spendry 7966053Spendry void 8066053Spendry union_updatevp(un, uppervp, lowervp) 8166051Spendry struct union_node *un; 8266053Spendry struct vnode *uppervp; 8366053Spendry struct vnode *lowervp; 8466051Spendry { 8566053Spendry int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); 8666053Spendry int nhash = UNION_HASH(uppervp, lowervp); 8766051Spendry 8866053Spendry if (ohash != nhash) { 8966053Spendry /* 9066053Spendry * Ensure locking is ordered from lower to higher 9166053Spendry * to avoid deadlocks. 9266053Spendry */ 9366053Spendry if (nhash < ohash) { 9466053Spendry int t = ohash; 9566053Spendry ohash = nhash; 9666053Spendry nhash = t; 9766051Spendry } 9866053Spendry 9966053Spendry while (union_list_lock(ohash)) 10066053Spendry continue; 10166053Spendry 10266053Spendry while (union_list_lock(nhash)) 10366053Spendry continue; 10466053Spendry 10566053Spendry LIST_REMOVE(un, un_cache); 10666053Spendry union_list_unlock(ohash); 10766053Spendry } else { 10866053Spendry while (union_list_lock(nhash)) 10966053Spendry continue; 11066051Spendry } 11166053Spendry 11266053Spendry if (un->un_lowervp != lowervp) { 11366053Spendry if (un->un_lowervp) { 11466053Spendry vrele(un->un_lowervp); 11566053Spendry if (un->un_path) { 11666053Spendry free(un->un_path, M_TEMP); 11766053Spendry un->un_path = 0; 11866053Spendry } 11966053Spendry if (un->un_dirvp) { 12066053Spendry vrele(un->un_dirvp); 12166053Spendry un->un_dirvp = NULLVP; 12266053Spendry } 12366053Spendry } 12466053Spendry un->un_lowervp = lowervp; 12566053Spendry } 12666053Spendry 12766053Spendry if (un->un_uppervp != uppervp) { 12866053Spendry if (un->un_uppervp) 12966053Spendry vrele(un->un_uppervp); 13066053Spendry 13166053Spendry un->un_uppervp = uppervp; 13266053Spendry } 13366053Spendry 13466053Spendry if (ohash != nhash) 13566053Spendry LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); 13666053Spendry 13766053Spendry union_list_unlock(nhash); 13866051Spendry } 13966051Spendry 14066053Spendry void 14166053Spendry union_newlower(un, lowervp) 14266053Spendry struct union_node *un; 14366053Spendry struct vnode *lowervp; 14466053Spendry { 14566053Spendry 14666053Spendry union_updatevp(un, un->un_uppervp, lowervp); 14766053Spendry } 14866053Spendry 14966053Spendry void 15066053Spendry union_newupper(un, uppervp) 15166053Spendry struct union_node *un; 15266053Spendry struct vnode *uppervp; 15366053Spendry { 15466053Spendry 15566053Spendry union_updatevp(un, uppervp, un->un_lowervp); 15666053Spendry } 15766053Spendry 15865934Spendry /* 15965934Spendry * allocate a union_node/vnode pair. the vnode is 16065965Spendry * referenced and locked. the new vnode is returned 16165965Spendry * via (vpp). (mp) is the mountpoint of the union filesystem, 16265965Spendry * (dvp) is the parent directory where the upper layer object 16365965Spendry * should exist (but doesn't) and (cnp) is the componentname 16465965Spendry * information which is partially copied to allow the upper 16565965Spendry * layer object to be created at a later time. (uppervp) 16665965Spendry * and (lowervp) reference the upper and lower layer objects 16765965Spendry * being mapped. either, but not both, can be nil. 16866051Spendry * if supplied, (uppervp) is locked. 16965997Spendry * the reference is either maintained in the new union_node 17065997Spendry * object which is allocated, or they are vrele'd. 17165934Spendry * 17265934Spendry * all union_nodes are maintained on a singly-linked 17365934Spendry * list. new nodes are only allocated when they cannot 17465934Spendry * be found on this list. entries on the list are 17565934Spendry * removed when the vfs reclaim entry is called. 17665934Spendry * 17765934Spendry * a single lock is kept for the entire list. this is 17865934Spendry * needed because the getnewvnode() function can block 17965934Spendry * waiting for a vnode to become free, in which case there 18065934Spendry * may be more than one process trying to get the same 18165934Spendry * vnode. this lock is only taken if we are going to 18265934Spendry * call getnewvnode, since the kernel itself is single-threaded. 18365934Spendry * 18465934Spendry * if an entry is found on the list, then call vget() to 18565934Spendry * take a reference. this is done because there may be 18665934Spendry * zero references to it and so it needs to removed from 18765934Spendry * the vnode free list. 18865934Spendry */ 18965934Spendry int 19065992Spendry union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp) 19165934Spendry struct vnode **vpp; 19265934Spendry struct mount *mp; 19365992Spendry struct vnode *undvp; 19465934Spendry struct vnode *dvp; /* may be null */ 19565934Spendry struct componentname *cnp; /* may be null */ 19665934Spendry struct vnode *uppervp; /* may be null */ 19765934Spendry struct vnode *lowervp; /* may be null */ 19865934Spendry { 19965934Spendry int error; 20065934Spendry struct union_node *un; 20165934Spendry struct union_node **pp; 20266053Spendry struct vnode *xlowervp = NULLVP; 20366053Spendry int hash; 20466053Spendry int try; 20565934Spendry 20666053Spendry if (uppervp == NULLVP && lowervp == NULLVP) 20765965Spendry panic("union: unidentifiable allocation"); 20865965Spendry 20965965Spendry if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { 21065965Spendry xlowervp = lowervp; 21166053Spendry lowervp = NULLVP; 21265965Spendry } 21365965Spendry 21465934Spendry loop: 21566053Spendry for (try = 0; try < 3; try++) { 21666053Spendry switch (try) { 21766053Spendry case 0: 21866053Spendry if (lowervp == NULLVP) 21966053Spendry continue; 22066053Spendry hash = UNION_HASH(uppervp, lowervp); 22166051Spendry break; 22266053Spendry 22366053Spendry case 1: 22466053Spendry if (uppervp == NULLVP) 22566053Spendry continue; 22666053Spendry hash = UNION_HASH(uppervp, NULLVP); 22766053Spendry break; 22866053Spendry 22966053Spendry case 2: 23066053Spendry if (lowervp == NULLVP) 23166053Spendry continue; 23266053Spendry hash = UNION_HASH(NULLVP, lowervp); 23366053Spendry break; 23466051Spendry } 23566053Spendry 23666053Spendry while (union_list_lock(hash)) 23766053Spendry continue; 23866053Spendry 23966053Spendry for (un = unhead[hash].lh_first; un != 0; 24066053Spendry un = un->un_cache.le_next) { 24166053Spendry if ((un->un_lowervp == lowervp || 24266053Spendry un->un_lowervp == NULLVP) && 24366053Spendry (un->un_uppervp == uppervp || 24466053Spendry un->un_uppervp == NULLVP) && 24566053Spendry (UNIONTOV(un)->v_mount == mp)) { 24666053Spendry if (vget(UNIONTOV(un), 0)) { 24766053Spendry union_list_unlock(hash); 24866053Spendry goto loop; 24966053Spendry } 25066053Spendry break; 25166053Spendry } 25266053Spendry } 25366053Spendry 25466053Spendry union_list_unlock(hash); 25566053Spendry 25666053Spendry if (un) 25766053Spendry break; 25866051Spendry } 25966027Spendry 26066051Spendry if (un) { 26166051Spendry /* 26266051Spendry * Obtain a lock on the union_node. 26366051Spendry * uppervp is locked, though un->un_uppervp 26466051Spendry * may not be. this doesn't break the locking 26566051Spendry * hierarchy since in the case that un->un_uppervp 26666051Spendry * is not yet locked it will be vrele'd and replaced 26766051Spendry * with uppervp. 26866051Spendry */ 26966051Spendry 27066051Spendry if ((dvp != NULLVP) && (uppervp == dvp)) { 27166027Spendry /* 27266051Spendry * Access ``.'', so (un) will already 27366051Spendry * be locked. Since this process has 27466051Spendry * the lock on (uppervp) no other 27566051Spendry * process can hold the lock on (un). 27666027Spendry */ 27766051Spendry #ifdef DIAGNOSTIC 27866051Spendry if ((un->un_flags & UN_LOCKED) == 0) 27966051Spendry panic("union: . not locked"); 28066051Spendry else if (curproc && un->un_pid != curproc->p_pid && 28166051Spendry un->un_pid > -1 && curproc->p_pid > -1) 28266051Spendry panic("union: allocvp not lock owner"); 28366051Spendry #endif 28466051Spendry } else { 28566051Spendry if (un->un_flags & UN_LOCKED) { 28666051Spendry vrele(UNIONTOV(un)); 28766051Spendry un->un_flags |= UN_WANT; 28866051Spendry sleep((caddr_t) &un->un_flags, PINOD); 28966051Spendry goto loop; 29065992Spendry } 29166051Spendry un->un_flags |= UN_LOCKED; 29266027Spendry 29366051Spendry #ifdef DIAGNOSTIC 29466051Spendry if (curproc) 29566051Spendry un->un_pid = curproc->p_pid; 29666051Spendry else 29766051Spendry un->un_pid = -1; 29866051Spendry #endif 29966051Spendry } 30066051Spendry 30166051Spendry /* 30266051Spendry * At this point, the union_node is locked, 30366051Spendry * un->un_uppervp may not be locked, and uppervp 30466051Spendry * is locked or nil. 30566051Spendry */ 30666051Spendry 30766051Spendry /* 30866051Spendry * Save information about the upper layer. 30966051Spendry */ 31066051Spendry if (uppervp != un->un_uppervp) { 31166053Spendry union_newupper(un, uppervp); 31266051Spendry } else if (uppervp) { 31366051Spendry vrele(uppervp); 31466051Spendry } 31566051Spendry 31666051Spendry if (un->un_uppervp) { 31766051Spendry un->un_flags |= UN_ULOCK; 31866051Spendry un->un_flags &= ~UN_KLOCK; 31966051Spendry } 32066051Spendry 32166051Spendry /* 32266051Spendry * Save information about the lower layer. 32366051Spendry * This needs to keep track of pathname 32466051Spendry * and directory information which union_vn_create 32566051Spendry * might need. 32666051Spendry */ 32766051Spendry if (lowervp != un->un_lowervp) { 32866053Spendry union_newlower(un, lowervp); 32966051Spendry if (cnp && (lowervp != NULLVP) && 33066051Spendry (lowervp->v_type == VREG)) { 33166051Spendry un->un_hash = cnp->cn_hash; 33266051Spendry un->un_path = malloc(cnp->cn_namelen+1, 33366051Spendry M_TEMP, M_WAITOK); 33466051Spendry bcopy(cnp->cn_nameptr, un->un_path, 33566051Spendry cnp->cn_namelen); 33666051Spendry un->un_path[cnp->cn_namelen] = '\0'; 33766051Spendry VREF(dvp); 33866051Spendry un->un_dirvp = dvp; 33966051Spendry } 34066051Spendry } else if (lowervp) { 34166051Spendry vrele(lowervp); 34265934Spendry } 34366051Spendry *vpp = UNIONTOV(un); 34466051Spendry return (0); 34565934Spendry } 34665934Spendry 34765934Spendry /* 34865934Spendry * otherwise lock the vp list while we call getnewvnode 34965934Spendry * since that can block. 35065934Spendry */ 35166053Spendry hash = UNION_HASH(uppervp, lowervp); 35266053Spendry 35366053Spendry if (union_list_lock(hash)) 35465934Spendry goto loop; 35565934Spendry 35665934Spendry error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); 35766051Spendry if (error) { 35866051Spendry if (uppervp) { 35966051Spendry if (dvp == uppervp) 36066051Spendry vrele(uppervp); 36166051Spendry else 36266051Spendry vput(uppervp); 36366051Spendry } 36466051Spendry if (lowervp) 36566051Spendry vrele(lowervp); 36666051Spendry 36765934Spendry goto out; 36866051Spendry } 36965934Spendry 37065934Spendry MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), 37165934Spendry M_TEMP, M_WAITOK); 37265934Spendry 37365965Spendry if (uppervp) 37465965Spendry (*vpp)->v_type = uppervp->v_type; 37565965Spendry else 37665965Spendry (*vpp)->v_type = lowervp->v_type; 37765934Spendry un = VTOUNION(*vpp); 37865992Spendry un->un_vnode = *vpp; 37965934Spendry un->un_uppervp = uppervp; 38065934Spendry un->un_lowervp = lowervp; 38166028Spendry un->un_openl = 0; 38266051Spendry un->un_flags = UN_LOCKED; 38366051Spendry if (un->un_uppervp) 38466051Spendry un->un_flags |= UN_ULOCK; 38566051Spendry #ifdef DIAGNOSTIC 38666051Spendry if (curproc) 38766051Spendry un->un_pid = curproc->p_pid; 38866051Spendry else 38966051Spendry un->un_pid = -1; 39066051Spendry #endif 39166027Spendry if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) { 39266027Spendry un->un_hash = cnp->cn_hash; 39365934Spendry un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); 39465934Spendry bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); 39565934Spendry un->un_path[cnp->cn_namelen] = '\0'; 39665965Spendry VREF(dvp); 39765965Spendry un->un_dirvp = dvp; 39865934Spendry } else { 39966027Spendry un->un_hash = 0; 40065934Spendry un->un_path = 0; 40165965Spendry un->un_dirvp = 0; 40265934Spendry } 40365934Spendry 40466053Spendry LIST_INSERT_HEAD(&unhead[hash], un, un_cache); 40565934Spendry 40665965Spendry if (xlowervp) 40765965Spendry vrele(xlowervp); 40865965Spendry 40965934Spendry out: 41066053Spendry union_list_unlock(hash); 41165934Spendry 41265934Spendry return (error); 41365934Spendry } 41465934Spendry 41565934Spendry int 41665934Spendry union_freevp(vp) 41765934Spendry struct vnode *vp; 41865934Spendry { 41965934Spendry struct union_node *un = VTOUNION(vp); 42065934Spendry 42166053Spendry LIST_REMOVE(un, un_cache); 42265934Spendry 42366053Spendry if (un->un_uppervp) 42466053Spendry vrele(un->un_uppervp); 42566053Spendry if (un->un_lowervp) 42666053Spendry vrele(un->un_lowervp); 42766053Spendry if (un->un_dirvp) 42866053Spendry vrele(un->un_dirvp); 42966053Spendry if (un->un_path) 43066053Spendry free(un->un_path, M_TEMP); 43166053Spendry 43265934Spendry FREE(vp->v_data, M_TEMP); 43365934Spendry vp->v_data = 0; 43466053Spendry 43565934Spendry return (0); 43665934Spendry } 43765994Spendry 43865994Spendry /* 43965994Spendry * copyfile. copy the vnode (fvp) to the vnode (tvp) 44065994Spendry * using a sequence of reads and writes. both (fvp) 44165994Spendry * and (tvp) are locked on entry and exit. 44265994Spendry */ 44365994Spendry int 44465994Spendry union_copyfile(p, cred, fvp, tvp) 44565994Spendry struct proc *p; 44665994Spendry struct ucred *cred; 44765994Spendry struct vnode *fvp; 44865994Spendry struct vnode *tvp; 44965994Spendry { 45065994Spendry char *buf; 45165994Spendry struct uio uio; 45265994Spendry struct iovec iov; 45365994Spendry int error = 0; 45465994Spendry 45565994Spendry /* 45665994Spendry * strategy: 45765994Spendry * allocate a buffer of size MAXBSIZE. 45865994Spendry * loop doing reads and writes, keeping track 45965994Spendry * of the current uio offset. 46065994Spendry * give up at the first sign of trouble. 46165994Spendry */ 46265994Spendry 46365994Spendry uio.uio_procp = p; 46465994Spendry uio.uio_segflg = UIO_SYSSPACE; 46565994Spendry uio.uio_offset = 0; 46665994Spendry 46765994Spendry VOP_UNLOCK(fvp); /* XXX */ 46865994Spendry LEASE_CHECK(fvp, p, cred, LEASE_READ); 46965994Spendry VOP_LOCK(fvp); /* XXX */ 47065994Spendry VOP_UNLOCK(tvp); /* XXX */ 47165994Spendry LEASE_CHECK(tvp, p, cred, LEASE_WRITE); 47265994Spendry VOP_LOCK(tvp); /* XXX */ 47365994Spendry 47465994Spendry buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); 47565994Spendry 47665994Spendry /* ugly loop follows... */ 47765994Spendry do { 47865994Spendry off_t offset = uio.uio_offset; 47965994Spendry 48065994Spendry uio.uio_iov = &iov; 48165994Spendry uio.uio_iovcnt = 1; 48265994Spendry iov.iov_base = buf; 48365994Spendry iov.iov_len = MAXBSIZE; 48465994Spendry uio.uio_resid = iov.iov_len; 48565994Spendry uio.uio_rw = UIO_READ; 48665994Spendry error = VOP_READ(fvp, &uio, 0, cred); 48765994Spendry 48865994Spendry if (error == 0) { 48965994Spendry uio.uio_iov = &iov; 49065994Spendry uio.uio_iovcnt = 1; 49165994Spendry iov.iov_base = buf; 49265994Spendry iov.iov_len = MAXBSIZE - uio.uio_resid; 49365994Spendry uio.uio_offset = offset; 49465994Spendry uio.uio_rw = UIO_WRITE; 49565994Spendry uio.uio_resid = iov.iov_len; 49665994Spendry 49765994Spendry if (uio.uio_resid == 0) 49865994Spendry break; 49965994Spendry 50065994Spendry do { 50165994Spendry error = VOP_WRITE(tvp, &uio, 0, cred); 50265994Spendry } while ((uio.uio_resid > 0) && (error == 0)); 50365994Spendry } 50465994Spendry 50565994Spendry } while (error == 0); 50665994Spendry 50765994Spendry free(buf, M_TEMP); 50865994Spendry return (error); 50965994Spendry } 51065994Spendry 51165994Spendry /* 51265997Spendry * Create a shadow directory in the upper layer. 51365997Spendry * The new vnode is returned locked. 51465997Spendry * 51565997Spendry * (um) points to the union mount structure for access to the 51665997Spendry * the mounting process's credentials. 51765997Spendry * (dvp) is the directory in which to create the shadow directory. 51865997Spendry * it is unlocked on entry and exit. 51965997Spendry * (cnp) is the componentname to be created. 52065997Spendry * (vpp) is the returned newly created shadow directory, which 52165997Spendry * is returned locked. 52265997Spendry */ 52365997Spendry int 52465997Spendry union_mkshadow(um, dvp, cnp, vpp) 52565997Spendry struct union_mount *um; 52665997Spendry struct vnode *dvp; 52765997Spendry struct componentname *cnp; 52865997Spendry struct vnode **vpp; 52965997Spendry { 53065997Spendry int error; 53165997Spendry struct vattr va; 53265997Spendry struct proc *p = cnp->cn_proc; 53365997Spendry struct componentname cn; 53465997Spendry 53565997Spendry /* 53665997Spendry * policy: when creating the shadow directory in the 53766034Spendry * upper layer, create it owned by the user who did 53866034Spendry * the mount, group from parent directory, and mode 53966034Spendry * 777 modified by umask (ie mostly identical to the 54066034Spendry * mkdir syscall). (jsp, kb) 54165997Spendry */ 54265997Spendry 54365997Spendry /* 54465997Spendry * A new componentname structure must be faked up because 54565997Spendry * there is no way to know where the upper level cnp came 54665997Spendry * from or what it is being used for. This must duplicate 54765997Spendry * some of the work done by NDINIT, some of the work done 54865997Spendry * by namei, some of the work done by lookup and some of 54965997Spendry * the work done by VOP_LOOKUP when given a CREATE flag. 55065997Spendry * Conclusion: Horrible. 55165997Spendry * 55265997Spendry * The pathname buffer will be FREEed by VOP_MKDIR. 55365997Spendry */ 55465997Spendry cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK); 55566027Spendry bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen); 55666027Spendry cn.cn_pnbuf[cnp->cn_namelen] = '\0'; 55765997Spendry 55865997Spendry cn.cn_nameiop = CREATE; 559*66060Spendry cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); 56065997Spendry cn.cn_proc = cnp->cn_proc; 56166034Spendry cn.cn_cred = um->um_cred; 56265997Spendry cn.cn_nameptr = cn.cn_pnbuf; 56365997Spendry cn.cn_namelen = cnp->cn_namelen; 56465997Spendry cn.cn_hash = cnp->cn_hash; 56565997Spendry cn.cn_consume = cnp->cn_consume; 56665997Spendry 56766027Spendry VREF(dvp); 56865997Spendry if (error = relookup(dvp, vpp, &cn)) 56965997Spendry return (error); 57066027Spendry vrele(dvp); 57165997Spendry 57265997Spendry if (*vpp) { 57365997Spendry VOP_ABORTOP(dvp, &cn); 57465997Spendry VOP_UNLOCK(dvp); 57565997Spendry vrele(*vpp); 57665997Spendry *vpp = NULLVP; 57765997Spendry return (EEXIST); 57865997Spendry } 57965997Spendry 58065997Spendry VATTR_NULL(&va); 58165997Spendry va.va_type = VDIR; 58266034Spendry va.va_mode = um->um_cmode; 58365997Spendry 58465997Spendry /* LEASE_CHECK: dvp is locked */ 58565997Spendry LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE); 58665997Spendry 58765997Spendry error = VOP_MKDIR(dvp, vpp, &cn, &va); 58865997Spendry return (error); 58965997Spendry } 59065997Spendry 59165997Spendry /* 59265994Spendry * union_vn_create: creates and opens a new shadow file 59365994Spendry * on the upper union layer. this function is similar 59465994Spendry * in spirit to calling vn_open but it avoids calling namei(). 59565994Spendry * the problem with calling namei is that a) it locks too many 59665994Spendry * things, and b) it doesn't start at the "right" directory, 59765994Spendry * whereas relookup is told where to start. 59865994Spendry */ 59965994Spendry int 60065997Spendry union_vn_create(vpp, un, p) 60165994Spendry struct vnode **vpp; 60265994Spendry struct union_node *un; 60365994Spendry struct proc *p; 60465994Spendry { 60565994Spendry struct vnode *vp; 60665994Spendry struct ucred *cred = p->p_ucred; 60765994Spendry struct vattr vat; 60865994Spendry struct vattr *vap = &vat; 60965994Spendry int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL); 61065994Spendry int error; 61166027Spendry int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask; 61265994Spendry char *cp; 61365994Spendry struct componentname cn; 61465994Spendry 61565994Spendry *vpp = NULLVP; 61665994Spendry 61766034Spendry /* 61866034Spendry * Build a new componentname structure (for the same 61966034Spendry * reasons outlines in union_mkshadow). 62066034Spendry * The difference here is that the file is owned by 62166034Spendry * the current user, rather than by the person who 62266034Spendry * did the mount, since the current user needs to be 62366034Spendry * able to write the file (that's why it is being 62466034Spendry * copied in the first place). 62566034Spendry */ 62665994Spendry cn.cn_namelen = strlen(un->un_path); 62765994Spendry cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen, M_NAMEI, M_WAITOK); 62865994Spendry bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1); 62965994Spendry cn.cn_nameiop = CREATE; 630*66060Spendry cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN); 63165994Spendry cn.cn_proc = p; 63265994Spendry cn.cn_cred = p->p_ucred; 63365994Spendry cn.cn_nameptr = cn.cn_pnbuf; 63466027Spendry cn.cn_hash = un->un_hash; 63565994Spendry cn.cn_consume = 0; 63665994Spendry 63766027Spendry VREF(un->un_dirvp); 63865994Spendry if (error = relookup(un->un_dirvp, &vp, &cn)) 63965994Spendry return (error); 64066027Spendry vrele(un->un_dirvp); 64166027Spendry 642*66060Spendry if (vp) { 64365994Spendry VOP_ABORTOP(un->un_dirvp, &cn); 64465994Spendry if (un->un_dirvp == vp) 64565994Spendry vrele(un->un_dirvp); 64665994Spendry else 647*66060Spendry vput(un->un_dirvp); 648*66060Spendry vrele(vp); 649*66060Spendry return (EEXIST); 65065994Spendry } 65165994Spendry 652*66060Spendry /* 653*66060Spendry * Good - there was no race to create the file 654*66060Spendry * so go ahead and create it. The permissions 655*66060Spendry * on the file will be 0666 modified by the 656*66060Spendry * current user's umask. Access to the file, while 657*66060Spendry * it is unioned, will require access to the top *and* 658*66060Spendry * bottom files. Access when not unioned will simply 659*66060Spendry * require access to the top-level file. 660*66060Spendry * TODO: confirm choice of access permissions. 661*66060Spendry */ 66265994Spendry VATTR_NULL(vap); 663*66060Spendry vap->va_type = VREG; 664*66060Spendry vap->va_mode = cmode; 665*66060Spendry LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE); 666*66060Spendry if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap)) 667*66060Spendry return (error); 66865994Spendry 669*66060Spendry if (error = VOP_OPEN(vp, fmode, cred, p)) { 670*66060Spendry vput(vp); 671*66060Spendry return (error); 672*66060Spendry } 67365994Spendry 67465994Spendry vp->v_writecount++; 67565994Spendry *vpp = vp; 67665994Spendry return (0); 67765994Spendry } 67866027Spendry 67966027Spendry int 68066028Spendry union_vn_close(vp, fmode, cred, p) 68166027Spendry struct vnode *vp; 68266027Spendry int fmode; 68366028Spendry struct ucred *cred; 68466028Spendry struct proc *p; 68566027Spendry { 68666027Spendry if (fmode & FWRITE) 68766027Spendry --vp->v_writecount; 68866027Spendry return (VOP_CLOSE(vp, fmode)); 68966027Spendry } 69066027Spendry 69166027Spendry void 69266027Spendry union_removed_upper(un) 69366027Spendry struct union_node *un; 69466027Spendry { 69566051Spendry if (un->un_flags & UN_ULOCK) { 69666051Spendry un->un_flags &= ~UN_ULOCK; 69766053Spendry VOP_UNLOCK(un->un_uppervp); 69866051Spendry } 69966053Spendry 70066053Spendry union_newupper(un, NULLVP); 70166027Spendry } 70266028Spendry 70366028Spendry struct vnode * 70466028Spendry union_lowervp(vp) 70566028Spendry struct vnode *vp; 70666028Spendry { 70766028Spendry struct union_node *un = VTOUNION(vp); 70866028Spendry 70966028Spendry if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) { 71066028Spendry if (vget(un->un_lowervp, 0)) 71166028Spendry return (NULLVP); 71266028Spendry } 71366028Spendry 71466028Spendry return (un->un_lowervp); 71566028Spendry } 716