1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1994 Jan-Simon Pendry 3df8bae1dSRodney W. Grimes * Copyright (c) 1994 4df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 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_subr.c 8.20 (Berkeley) 5/20/95 38c3aac50fSPeter Wemm * $FreeBSD$ 39df8bae1dSRodney W. Grimes */ 40df8bae1dSRodney W. Grimes 41df8bae1dSRodney W. Grimes #include <sys/param.h> 42df8bae1dSRodney W. Grimes #include <sys/systm.h> 433ac4d1efSBruce Evans #include <sys/fcntl.h> 448c14bf40SPeter Wemm #include <sys/file.h> 45df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 46fb919e4dSMark Murray #include <sys/kernel.h> 47fb919e4dSMark Murray #include <sys/lock.h> 48fb919e4dSMark Murray #include <sys/malloc.h> 498c14bf40SPeter Wemm #include <sys/module.h> 50996c772fSJohn Dyson #include <sys/mount.h> 51fb919e4dSMark Murray #include <sys/namei.h> 52996c772fSJohn Dyson #include <sys/stat.h> 53fb919e4dSMark Murray #include <sys/vnode.h> 54fb919e4dSMark Murray 55724ab195SMike Pritchard #include <vm/vm.h> 56724ab195SMike Pritchard #include <vm/vm_extern.h> /* for vnode_pager_setsize */ 57675ea6f0SBruce Evans #include <vm/vm_zone.h> 582a31267eSMatthew Dillon #include <vm/vm_object.h> /* for vm cache coherency */ 59fb919e4dSMark Murray 60df8bae1dSRodney W. Grimes #include <miscfs/union/union.h> 61df8bae1dSRodney W. Grimes 62df8bae1dSRodney W. Grimes #include <sys/proc.h> 63df8bae1dSRodney W. Grimes 649b5e8b3aSBruce Evans extern int union_init __P((void)); 659b5e8b3aSBruce Evans 66df8bae1dSRodney W. Grimes /* must be power of two, otherwise change UNION_HASH() */ 67df8bae1dSRodney W. Grimes #define NHASH 32 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes /* unsigned int ... */ 70df8bae1dSRodney W. Grimes #define UNION_HASH(u, l) \ 7115c73825SBruce Evans (((((uintptr_t) (u)) + ((uintptr_t) l)) >> 8) & (NHASH-1)) 72df8bae1dSRodney W. Grimes 73e3975643SJake Burkholder static LIST_HEAD(unhead, union_node) unhead[NHASH]; 74df8bae1dSRodney W. Grimes static int unvplock[NHASH]; 75df8bae1dSRodney W. Grimes 76938958b9SBruce Evans static void union_dircache_r __P((struct vnode *vp, struct vnode ***vppp, 77938958b9SBruce Evans int *cntp)); 789b5e8b3aSBruce Evans static int union_list_lock __P((int ix)); 799b5e8b3aSBruce Evans static void union_list_unlock __P((int ix)); 80938958b9SBruce Evans static int union_relookup __P((struct union_mount *um, struct vnode *dvp, 81938958b9SBruce Evans struct vnode **vpp, 82938958b9SBruce Evans struct componentname *cnp, 83938958b9SBruce Evans struct componentname *cn, char *path, 84938958b9SBruce Evans int pathlen)); 8580b301c3SPoul-Henning Kamp static void union_updatevp __P((struct union_node *un, 869b5e8b3aSBruce Evans struct vnode *uppervp, 879b5e8b3aSBruce Evans struct vnode *lowervp)); 8880b301c3SPoul-Henning Kamp static void union_newlower __P((struct union_node *, struct vnode *)); 8980b301c3SPoul-Henning Kamp static void union_newupper __P((struct union_node *, struct vnode *)); 9080b301c3SPoul-Henning Kamp static int union_copyfile __P((struct vnode *, struct vnode *, 9180b301c3SPoul-Henning Kamp struct ucred *, struct proc *)); 9280b301c3SPoul-Henning Kamp static int union_vn_create __P((struct vnode **, struct union_node *, 9380b301c3SPoul-Henning Kamp struct proc *)); 9480b301c3SPoul-Henning Kamp static int union_vn_close __P((struct vnode *, int, struct ucred *, 9580b301c3SPoul-Henning Kamp struct proc *)); 969b5e8b3aSBruce Evans 97df8bae1dSRodney W. Grimes int 98df8bae1dSRodney W. Grimes union_init() 99df8bae1dSRodney W. Grimes { 100df8bae1dSRodney W. Grimes int i; 101df8bae1dSRodney W. Grimes 102df8bae1dSRodney W. Grimes for (i = 0; i < NHASH; i++) 103df8bae1dSRodney W. Grimes LIST_INIT(&unhead[i]); 104df8bae1dSRodney W. Grimes bzero((caddr_t)unvplock, sizeof(unvplock)); 10526f9a767SRodney W. Grimes return (0); 106df8bae1dSRodney W. Grimes } 107df8bae1dSRodney W. Grimes 108df8bae1dSRodney W. Grimes static int 109df8bae1dSRodney W. Grimes union_list_lock(ix) 110df8bae1dSRodney W. Grimes int ix; 111df8bae1dSRodney W. Grimes { 1122a31267eSMatthew Dillon if (unvplock[ix] & UNVP_LOCKED) { 1132a31267eSMatthew Dillon unvplock[ix] |= UNVP_WANT; 11482478919SDavid Greenman (void) tsleep((caddr_t) &unvplock[ix], PINOD, "unllck", 0); 115df8bae1dSRodney W. Grimes return (1); 116df8bae1dSRodney W. Grimes } 1172a31267eSMatthew Dillon unvplock[ix] |= UNVP_LOCKED; 118df8bae1dSRodney W. Grimes return (0); 119df8bae1dSRodney W. Grimes } 120df8bae1dSRodney W. Grimes 121df8bae1dSRodney W. Grimes static void 122df8bae1dSRodney W. Grimes union_list_unlock(ix) 123df8bae1dSRodney W. Grimes int ix; 124df8bae1dSRodney W. Grimes { 1252a31267eSMatthew Dillon unvplock[ix] &= ~UNVP_LOCKED; 126df8bae1dSRodney W. Grimes 1272a31267eSMatthew Dillon if (unvplock[ix] & UNVP_WANT) { 1282a31267eSMatthew Dillon unvplock[ix] &= ~UNVP_WANT; 129df8bae1dSRodney W. Grimes wakeup((caddr_t) &unvplock[ix]); 130df8bae1dSRodney W. Grimes } 131df8bae1dSRodney W. Grimes } 132df8bae1dSRodney W. Grimes 1332a31267eSMatthew Dillon /* 1342a31267eSMatthew Dillon * union_updatevp: 1352a31267eSMatthew Dillon * 1362a31267eSMatthew Dillon * The uppervp, if not NULL, must be referenced and not locked by us 1372a31267eSMatthew Dillon * The lowervp, if not NULL, must be referenced. 1382a31267eSMatthew Dillon * 1392a31267eSMatthew Dillon * if uppervp and lowervp match pointers already installed, nothing 1402a31267eSMatthew Dillon * happens. The passed vp's (when matching) are not adjusted. This 1412a31267eSMatthew Dillon * routine may only be called by union_newupper() and union_newlower(). 1422a31267eSMatthew Dillon */ 1432a31267eSMatthew Dillon 14480b301c3SPoul-Henning Kamp static void 145df8bae1dSRodney W. Grimes union_updatevp(un, uppervp, lowervp) 146df8bae1dSRodney W. Grimes struct union_node *un; 147df8bae1dSRodney W. Grimes struct vnode *uppervp; 148df8bae1dSRodney W. Grimes struct vnode *lowervp; 149df8bae1dSRodney W. Grimes { 150df8bae1dSRodney W. Grimes int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); 151df8bae1dSRodney W. Grimes int nhash = UNION_HASH(uppervp, lowervp); 152996c772fSJohn Dyson int docache = (lowervp != NULLVP || uppervp != NULLVP); 15380b301c3SPoul-Henning Kamp int lhash, uhash; 154df8bae1dSRodney W. Grimes 155df8bae1dSRodney W. Grimes /* 156df8bae1dSRodney W. Grimes * Ensure locking is ordered from lower to higher 157df8bae1dSRodney W. Grimes * to avoid deadlocks. 158df8bae1dSRodney W. Grimes */ 159df8bae1dSRodney W. Grimes if (nhash < ohash) { 160996c772fSJohn Dyson lhash = nhash; 161996c772fSJohn Dyson uhash = ohash; 162df8bae1dSRodney W. Grimes } else { 163996c772fSJohn Dyson lhash = ohash; 164996c772fSJohn Dyson uhash = nhash; 165df8bae1dSRodney W. Grimes } 166df8bae1dSRodney W. Grimes 1672a31267eSMatthew Dillon if (lhash != uhash) { 168996c772fSJohn Dyson while (union_list_lock(lhash)) 169996c772fSJohn Dyson continue; 1702a31267eSMatthew Dillon } 171996c772fSJohn Dyson 172996c772fSJohn Dyson while (union_list_lock(uhash)) 173996c772fSJohn Dyson continue; 174996c772fSJohn Dyson 175996c772fSJohn Dyson if (ohash != nhash || !docache) { 176996c772fSJohn Dyson if (un->un_flags & UN_CACHED) { 177996c772fSJohn Dyson un->un_flags &= ~UN_CACHED; 178996c772fSJohn Dyson LIST_REMOVE(un, un_cache); 179996c772fSJohn Dyson } 180996c772fSJohn Dyson } 181996c772fSJohn Dyson 182996c772fSJohn Dyson if (ohash != nhash) 183996c772fSJohn Dyson union_list_unlock(ohash); 184996c772fSJohn Dyson 185df8bae1dSRodney W. Grimes if (un->un_lowervp != lowervp) { 186df8bae1dSRodney W. Grimes if (un->un_lowervp) { 187df8bae1dSRodney W. Grimes vrele(un->un_lowervp); 188df8bae1dSRodney W. Grimes if (un->un_path) { 189df8bae1dSRodney W. Grimes free(un->un_path, M_TEMP); 190df8bae1dSRodney W. Grimes un->un_path = 0; 191df8bae1dSRodney W. Grimes } 192df8bae1dSRodney W. Grimes } 193df8bae1dSRodney W. Grimes un->un_lowervp = lowervp; 194996c772fSJohn Dyson un->un_lowersz = VNOVAL; 195df8bae1dSRodney W. Grimes } 196df8bae1dSRodney W. Grimes 197df8bae1dSRodney W. Grimes if (un->un_uppervp != uppervp) { 198df8bae1dSRodney W. Grimes if (un->un_uppervp) 199df8bae1dSRodney W. Grimes vrele(un->un_uppervp); 200df8bae1dSRodney W. Grimes un->un_uppervp = uppervp; 201996c772fSJohn Dyson un->un_uppersz = VNOVAL; 202df8bae1dSRodney W. Grimes } 203df8bae1dSRodney W. Grimes 204996c772fSJohn Dyson if (docache && (ohash != nhash)) { 205df8bae1dSRodney W. Grimes LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); 206996c772fSJohn Dyson un->un_flags |= UN_CACHED; 207996c772fSJohn Dyson } 208df8bae1dSRodney W. Grimes 209df8bae1dSRodney W. Grimes union_list_unlock(nhash); 210df8bae1dSRodney W. Grimes } 211df8bae1dSRodney W. Grimes 2122a31267eSMatthew Dillon /* 2132a31267eSMatthew Dillon * Set a new lowervp. The passed lowervp must be referenced and will be 2142a31267eSMatthew Dillon * stored in the vp in a referenced state. 2152a31267eSMatthew Dillon */ 2162a31267eSMatthew Dillon 21780b301c3SPoul-Henning Kamp static void 218df8bae1dSRodney W. Grimes union_newlower(un, lowervp) 219df8bae1dSRodney W. Grimes struct union_node *un; 220df8bae1dSRodney W. Grimes struct vnode *lowervp; 221df8bae1dSRodney W. Grimes { 222df8bae1dSRodney W. Grimes union_updatevp(un, un->un_uppervp, lowervp); 223df8bae1dSRodney W. Grimes } 224df8bae1dSRodney W. Grimes 2252a31267eSMatthew Dillon /* 2262a31267eSMatthew Dillon * Set a new uppervp. The passed uppervp must be locked and will be 2272a31267eSMatthew Dillon * stored in the vp in a locked state. The caller should not unlock 2282a31267eSMatthew Dillon * uppervp. 2292a31267eSMatthew Dillon */ 2302a31267eSMatthew Dillon 23180b301c3SPoul-Henning Kamp static void 232df8bae1dSRodney W. Grimes union_newupper(un, uppervp) 233df8bae1dSRodney W. Grimes struct union_node *un; 234df8bae1dSRodney W. Grimes struct vnode *uppervp; 235df8bae1dSRodney W. Grimes { 236df8bae1dSRodney W. Grimes union_updatevp(un, uppervp, un->un_lowervp); 237df8bae1dSRodney W. Grimes } 238df8bae1dSRodney W. Grimes 239df8bae1dSRodney W. Grimes /* 240996c772fSJohn Dyson * Keep track of size changes in the underlying vnodes. 241996c772fSJohn Dyson * If the size changes, then callback to the vm layer 242996c772fSJohn Dyson * giving priority to the upper layer size. 243996c772fSJohn Dyson */ 244996c772fSJohn Dyson void 245996c772fSJohn Dyson union_newsize(vp, uppersz, lowersz) 246996c772fSJohn Dyson struct vnode *vp; 247996c772fSJohn Dyson off_t uppersz, lowersz; 248996c772fSJohn Dyson { 249996c772fSJohn Dyson struct union_node *un; 250996c772fSJohn Dyson off_t sz; 251996c772fSJohn Dyson 252996c772fSJohn Dyson /* only interested in regular files */ 253996c772fSJohn Dyson if (vp->v_type != VREG) 254996c772fSJohn Dyson return; 255996c772fSJohn Dyson 256996c772fSJohn Dyson un = VTOUNION(vp); 257996c772fSJohn Dyson sz = VNOVAL; 258996c772fSJohn Dyson 259996c772fSJohn Dyson if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) { 260996c772fSJohn Dyson un->un_uppersz = uppersz; 261996c772fSJohn Dyson if (sz == VNOVAL) 262996c772fSJohn Dyson sz = un->un_uppersz; 263996c772fSJohn Dyson } 264996c772fSJohn Dyson 265996c772fSJohn Dyson if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) { 266996c772fSJohn Dyson un->un_lowersz = lowersz; 267996c772fSJohn Dyson if (sz == VNOVAL) 268996c772fSJohn Dyson sz = un->un_lowersz; 269996c772fSJohn Dyson } 270996c772fSJohn Dyson 271996c772fSJohn Dyson if (sz != VNOVAL) { 2722a31267eSMatthew Dillon UDEBUG(("union: %s size now %ld\n", 2732a31267eSMatthew Dillon (uppersz != VNOVAL ? "upper" : "lower"), (long)sz)); 2743413421bSBoris Popov /* 2753413421bSBoris Popov * There is no need to change size of non-existent object 2763413421bSBoris Popov */ 2773413421bSBoris Popov /* vnode_pager_setsize(vp, sz); */ 278996c772fSJohn Dyson } 279996c772fSJohn Dyson } 280996c772fSJohn Dyson 281996c772fSJohn Dyson /* 2822a31267eSMatthew Dillon * union_allocvp: allocate a union_node and associate it with a 2832a31267eSMatthew Dillon * parent union_node and one or two vnodes. 2842a31267eSMatthew Dillon * 2852a31267eSMatthew Dillon * vpp Holds the returned vnode locked and referenced if no 2862a31267eSMatthew Dillon * error occurs. 2872a31267eSMatthew Dillon * 2882a31267eSMatthew Dillon * mp Holds the mount point. mp may or may not be busied. 2892a31267eSMatthew Dillon * allocvp makes no changes to mp. 2902a31267eSMatthew Dillon * 2912a31267eSMatthew Dillon * dvp Holds the parent union_node to the one we wish to create. 2922a31267eSMatthew Dillon * XXX may only be used to traverse an uncopied lowervp-based 2932a31267eSMatthew Dillon * tree? XXX 2942a31267eSMatthew Dillon * 2952a31267eSMatthew Dillon * dvp may or may not be locked. allocvp makes no changes 2962a31267eSMatthew Dillon * to dvp. 2972a31267eSMatthew Dillon * 2982a31267eSMatthew Dillon * upperdvp Holds the parent vnode to uppervp, generally used along 2992a31267eSMatthew Dillon * with path component information to create a shadow of 3002a31267eSMatthew Dillon * lowervp when uppervp does not exist. 3012a31267eSMatthew Dillon * 3022a31267eSMatthew Dillon * upperdvp is referenced but unlocked on entry, and will be 3032a31267eSMatthew Dillon * dereferenced on return. 3042a31267eSMatthew Dillon * 3052a31267eSMatthew Dillon * uppervp Holds the new uppervp vnode to be stored in the 3062a31267eSMatthew Dillon * union_node we are allocating. uppervp is referenced but 3072a31267eSMatthew Dillon * not locked, and will be dereferenced on return. 3082a31267eSMatthew Dillon * 3092a31267eSMatthew Dillon * lowervp Holds the new lowervp vnode to be stored in the 3109dbd7336SBoris Popov * union_node we are allocating. lowervp is referenced but 3112a31267eSMatthew Dillon * not locked, and will be dereferenced on return. 3122a31267eSMatthew Dillon * 3132a31267eSMatthew Dillon * cnp Holds path component information to be coupled with 3142a31267eSMatthew Dillon * lowervp and upperdvp to allow unionfs to create an uppervp 3152a31267eSMatthew Dillon * later on. Only used if lowervp is valid. The conents 3162a31267eSMatthew Dillon * of cnp is only valid for the duration of the call. 3172a31267eSMatthew Dillon * 3182a31267eSMatthew Dillon * docache Determine whether this node should be entered in the 3192a31267eSMatthew Dillon * cache or whether it should be destroyed as soon as possible. 320df8bae1dSRodney W. Grimes * 321df8bae1dSRodney W. Grimes * all union_nodes are maintained on a singly-linked 322df8bae1dSRodney W. Grimes * list. new nodes are only allocated when they cannot 323df8bae1dSRodney W. Grimes * be found on this list. entries on the list are 324df8bae1dSRodney W. Grimes * removed when the vfs reclaim entry is called. 325df8bae1dSRodney W. Grimes * 326df8bae1dSRodney W. Grimes * a single lock is kept for the entire list. this is 327df8bae1dSRodney W. Grimes * needed because the getnewvnode() function can block 328df8bae1dSRodney W. Grimes * waiting for a vnode to become free, in which case there 329df8bae1dSRodney W. Grimes * may be more than one process trying to get the same 330df8bae1dSRodney W. Grimes * vnode. this lock is only taken if we are going to 331df8bae1dSRodney W. Grimes * call getnewvnode, since the kernel itself is single-threaded. 332df8bae1dSRodney W. Grimes * 333df8bae1dSRodney W. Grimes * if an entry is found on the list, then call vget() to 334df8bae1dSRodney W. Grimes * take a reference. this is done because there may be 335df8bae1dSRodney W. Grimes * zero references to it and so it needs to removed from 336df8bae1dSRodney W. Grimes * the vnode free list. 337df8bae1dSRodney W. Grimes */ 3382a31267eSMatthew Dillon 339df8bae1dSRodney W. Grimes int 3402a31267eSMatthew Dillon union_allocvp(vpp, mp, dvp, upperdvp, cnp, uppervp, lowervp, docache) 341df8bae1dSRodney W. Grimes struct vnode **vpp; 342df8bae1dSRodney W. Grimes struct mount *mp; 3432a31267eSMatthew Dillon struct vnode *dvp; /* parent union vnode */ 3442a31267eSMatthew Dillon struct vnode *upperdvp; /* parent vnode of uppervp */ 345df8bae1dSRodney W. Grimes struct componentname *cnp; /* may be null */ 346df8bae1dSRodney W. Grimes struct vnode *uppervp; /* may be null */ 347df8bae1dSRodney W. Grimes struct vnode *lowervp; /* may be null */ 348996c772fSJohn Dyson int docache; 349df8bae1dSRodney W. Grimes { 350df8bae1dSRodney W. Grimes int error; 35126f9a767SRodney W. Grimes struct union_node *un = 0; 352996c772fSJohn Dyson struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 3532a31267eSMatthew Dillon struct proc *p = (cnp) ? cnp->cn_proc : curproc; 35427ed09c2SMatthew Dillon int hash = 0; 355996c772fSJohn Dyson int vflag; 356df8bae1dSRodney W. Grimes int try; 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes if (uppervp == NULLVP && lowervp == NULLVP) 359df8bae1dSRodney W. Grimes panic("union: unidentifiable allocation"); 360df8bae1dSRodney W. Grimes 361df8bae1dSRodney W. Grimes if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { 3629dbd7336SBoris Popov vrele(lowervp); 363df8bae1dSRodney W. Grimes lowervp = NULLVP; 364df8bae1dSRodney W. Grimes } 365df8bae1dSRodney W. Grimes 366996c772fSJohn Dyson /* detect the root vnode (and aliases) */ 367996c772fSJohn Dyson vflag = 0; 368996c772fSJohn Dyson if ((uppervp == um->um_uppervp) && 369996c772fSJohn Dyson ((lowervp == NULLVP) || lowervp == um->um_lowervp)) { 370996c772fSJohn Dyson if (lowervp == NULLVP) { 371996c772fSJohn Dyson lowervp = um->um_lowervp; 372996c772fSJohn Dyson if (lowervp != NULLVP) 373996c772fSJohn Dyson VREF(lowervp); 374996c772fSJohn Dyson } 375996c772fSJohn Dyson vflag = VROOT; 376996c772fSJohn Dyson } 377996c772fSJohn Dyson 378df8bae1dSRodney W. Grimes loop: 379996c772fSJohn Dyson if (!docache) { 380996c772fSJohn Dyson un = 0; 381996c772fSJohn Dyson } else for (try = 0; try < 3; try++) { 382df8bae1dSRodney W. Grimes switch (try) { 383df8bae1dSRodney W. Grimes case 0: 384df8bae1dSRodney W. Grimes if (lowervp == NULLVP) 385df8bae1dSRodney W. Grimes continue; 386df8bae1dSRodney W. Grimes hash = UNION_HASH(uppervp, lowervp); 387df8bae1dSRodney W. Grimes break; 388df8bae1dSRodney W. Grimes 389df8bae1dSRodney W. Grimes case 1: 390df8bae1dSRodney W. Grimes if (uppervp == NULLVP) 391df8bae1dSRodney W. Grimes continue; 392df8bae1dSRodney W. Grimes hash = UNION_HASH(uppervp, NULLVP); 393df8bae1dSRodney W. Grimes break; 394df8bae1dSRodney W. Grimes 395df8bae1dSRodney W. Grimes case 2: 396df8bae1dSRodney W. Grimes if (lowervp == NULLVP) 397df8bae1dSRodney W. Grimes continue; 398df8bae1dSRodney W. Grimes hash = UNION_HASH(NULLVP, lowervp); 399df8bae1dSRodney W. Grimes break; 400df8bae1dSRodney W. Grimes } 401df8bae1dSRodney W. Grimes 402df8bae1dSRodney W. Grimes while (union_list_lock(hash)) 403df8bae1dSRodney W. Grimes continue; 404df8bae1dSRodney W. Grimes 405ef9e85abSPoul-Henning Kamp LIST_FOREACH(un, &unhead[hash], un_cache) { 406df8bae1dSRodney W. Grimes if ((un->un_lowervp == lowervp || 407df8bae1dSRodney W. Grimes un->un_lowervp == NULLVP) && 408df8bae1dSRodney W. Grimes (un->un_uppervp == uppervp || 409df8bae1dSRodney W. Grimes un->un_uppervp == NULLVP) && 410df8bae1dSRodney W. Grimes (UNIONTOV(un)->v_mount == mp)) { 411996c772fSJohn Dyson if (vget(UNIONTOV(un), 0, 412996c772fSJohn Dyson cnp ? cnp->cn_proc : NULL)) { 413df8bae1dSRodney W. Grimes union_list_unlock(hash); 414df8bae1dSRodney W. Grimes goto loop; 415df8bae1dSRodney W. Grimes } 416df8bae1dSRodney W. Grimes break; 417df8bae1dSRodney W. Grimes } 418df8bae1dSRodney W. Grimes } 419df8bae1dSRodney W. Grimes 420df8bae1dSRodney W. Grimes union_list_unlock(hash); 421df8bae1dSRodney W. Grimes 422df8bae1dSRodney W. Grimes if (un) 423df8bae1dSRodney W. Grimes break; 424df8bae1dSRodney W. Grimes } 425df8bae1dSRodney W. Grimes 426df8bae1dSRodney W. Grimes if (un) { 427df8bae1dSRodney W. Grimes /* 4282a31267eSMatthew Dillon * Obtain a lock on the union_node. Everything is unlocked 4292a31267eSMatthew Dillon * except for dvp, so check that case. If they match, our 4302a31267eSMatthew Dillon * new un is already locked. Otherwise we have to lock our 4312a31267eSMatthew Dillon * new un. 4322a31267eSMatthew Dillon * 4332a31267eSMatthew Dillon * A potential deadlock situation occurs when we are holding 4342a31267eSMatthew Dillon * one lock while trying to get another. We must follow 4352a31267eSMatthew Dillon * strict ordering rules to avoid it. We try to locate dvp 4362a31267eSMatthew Dillon * by scanning up from un_vnode, since the most likely 4372a31267eSMatthew Dillon * scenario is un being under dvp. 438df8bae1dSRodney W. Grimes */ 439df8bae1dSRodney W. Grimes 4402a31267eSMatthew Dillon if (dvp && un->un_vnode != dvp) { 4412a31267eSMatthew Dillon struct vnode *scan = un->un_vnode; 4422a31267eSMatthew Dillon 4432a31267eSMatthew Dillon do { 4442a31267eSMatthew Dillon scan = VTOUNION(scan)->un_pvp; 4452a31267eSMatthew Dillon } while (scan && scan->v_tag == VT_UNION && scan != dvp); 4462a31267eSMatthew Dillon if (scan != dvp) { 447df8bae1dSRodney W. Grimes /* 4482a31267eSMatthew Dillon * our new un is above dvp (we never saw dvp 4492a31267eSMatthew Dillon * while moving up the tree). 450df8bae1dSRodney W. Grimes */ 4512a31267eSMatthew Dillon VREF(dvp); 4522a31267eSMatthew Dillon VOP_UNLOCK(dvp, 0, p); 4532a31267eSMatthew Dillon error = vn_lock(un->un_vnode, LK_EXCLUSIVE, p); 4542a31267eSMatthew Dillon vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 4552a31267eSMatthew Dillon vrele(dvp); 456df8bae1dSRodney W. Grimes } else { 4572a31267eSMatthew Dillon /* 4582a31267eSMatthew Dillon * our new un is under dvp 4592a31267eSMatthew Dillon */ 4602a31267eSMatthew Dillon error = vn_lock(un->un_vnode, LK_EXCLUSIVE, p); 4612a31267eSMatthew Dillon } 4622a31267eSMatthew Dillon } else if (dvp == NULLVP) { 4632a31267eSMatthew Dillon /* 4642a31267eSMatthew Dillon * dvp is NULL, we need to lock un. 4652a31267eSMatthew Dillon */ 4662a31267eSMatthew Dillon error = vn_lock(un->un_vnode, LK_EXCLUSIVE, p); 4672a31267eSMatthew Dillon } else { 4682a31267eSMatthew Dillon /* 4692a31267eSMatthew Dillon * dvp == un->un_vnode, we are already locked. 4702a31267eSMatthew Dillon */ 4712a31267eSMatthew Dillon error = 0; 4722a31267eSMatthew Dillon } 4732a31267eSMatthew Dillon 4742a31267eSMatthew Dillon if (error) 475df8bae1dSRodney W. Grimes goto loop; 476df8bae1dSRodney W. Grimes 477df8bae1dSRodney W. Grimes /* 4782a31267eSMatthew Dillon * At this point, the union_node is locked and referenced. 4792a31267eSMatthew Dillon * 4802a31267eSMatthew Dillon * uppervp is locked and referenced or NULL, lowervp is 4812a31267eSMatthew Dillon * referenced or NULL. 482df8bae1dSRodney W. Grimes */ 4832a31267eSMatthew Dillon UDEBUG(("Modify existing un %p vn %p upper %p(refs %d) -> %p(refs %d)\n", 4842a31267eSMatthew Dillon un, un->un_vnode, un->un_uppervp, 4852a31267eSMatthew Dillon (un->un_uppervp ? un->un_uppervp->v_usecount : -99), 4862a31267eSMatthew Dillon uppervp, 4872a31267eSMatthew Dillon (uppervp ? uppervp->v_usecount : -99) 4882a31267eSMatthew Dillon )); 489df8bae1dSRodney W. Grimes 490df8bae1dSRodney W. Grimes if (uppervp != un->un_uppervp) { 4912a31267eSMatthew Dillon KASSERT(uppervp == NULL || uppervp->v_usecount > 0, ("union_allocvp: too few refs %d (at least 1 required) on uppervp", uppervp->v_usecount)); 492df8bae1dSRodney W. Grimes union_newupper(un, uppervp); 493df8bae1dSRodney W. Grimes } else if (uppervp) { 4942a31267eSMatthew Dillon KASSERT(uppervp->v_usecount > 1, ("union_allocvp: too few refs %d (at least 2 required) on uppervp", uppervp->v_usecount)); 495df8bae1dSRodney W. Grimes vrele(uppervp); 496df8bae1dSRodney W. Grimes } 497df8bae1dSRodney W. Grimes 498df8bae1dSRodney W. Grimes /* 499df8bae1dSRodney W. Grimes * Save information about the lower layer. 500df8bae1dSRodney W. Grimes * This needs to keep track of pathname 501df8bae1dSRodney W. Grimes * and directory information which union_vn_create 502df8bae1dSRodney W. Grimes * might need. 503df8bae1dSRodney W. Grimes */ 504df8bae1dSRodney W. Grimes if (lowervp != un->un_lowervp) { 505df8bae1dSRodney W. Grimes union_newlower(un, lowervp); 506996c772fSJohn Dyson if (cnp && (lowervp != NULLVP)) { 507df8bae1dSRodney W. Grimes un->un_path = malloc(cnp->cn_namelen+1, 508df8bae1dSRodney W. Grimes M_TEMP, M_WAITOK); 509df8bae1dSRodney W. Grimes bcopy(cnp->cn_nameptr, un->un_path, 510df8bae1dSRodney W. Grimes cnp->cn_namelen); 511df8bae1dSRodney W. Grimes un->un_path[cnp->cn_namelen] = '\0'; 512df8bae1dSRodney W. Grimes } 513df8bae1dSRodney W. Grimes } else if (lowervp) { 514df8bae1dSRodney W. Grimes vrele(lowervp); 515df8bae1dSRodney W. Grimes } 5162a31267eSMatthew Dillon 5172a31267eSMatthew Dillon /* 5182a31267eSMatthew Dillon * and upperdvp 5192a31267eSMatthew Dillon */ 5202a31267eSMatthew Dillon if (upperdvp != un->un_dirvp) { 5212a31267eSMatthew Dillon if (un->un_dirvp) 5222a31267eSMatthew Dillon vrele(un->un_dirvp); 5232a31267eSMatthew Dillon un->un_dirvp = upperdvp; 5242a31267eSMatthew Dillon } else if (upperdvp) { 5252a31267eSMatthew Dillon vrele(upperdvp); 5262a31267eSMatthew Dillon } 5272a31267eSMatthew Dillon 528df8bae1dSRodney W. Grimes *vpp = UNIONTOV(un); 529df8bae1dSRodney W. Grimes return (0); 530df8bae1dSRodney W. Grimes } 531df8bae1dSRodney W. Grimes 532996c772fSJohn Dyson if (docache) { 533df8bae1dSRodney W. Grimes /* 534df8bae1dSRodney W. Grimes * otherwise lock the vp list while we call getnewvnode 535df8bae1dSRodney W. Grimes * since that can block. 536df8bae1dSRodney W. Grimes */ 537df8bae1dSRodney W. Grimes hash = UNION_HASH(uppervp, lowervp); 538df8bae1dSRodney W. Grimes 539df8bae1dSRodney W. Grimes if (union_list_lock(hash)) 540df8bae1dSRodney W. Grimes goto loop; 541996c772fSJohn Dyson } 542df8bae1dSRodney W. Grimes 5432a31267eSMatthew Dillon /* 5442a31267eSMatthew Dillon * Create new node rather then replace old node 5452a31267eSMatthew Dillon */ 5462a31267eSMatthew Dillon 547df8bae1dSRodney W. Grimes error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); 548df8bae1dSRodney W. Grimes if (error) { 5492a31267eSMatthew Dillon /* 5502a31267eSMatthew Dillon * If an error occurs clear out vnodes. 5512a31267eSMatthew Dillon */ 552df8bae1dSRodney W. Grimes if (lowervp) 553df8bae1dSRodney W. Grimes vrele(lowervp); 5542a31267eSMatthew Dillon if (uppervp) 5552a31267eSMatthew Dillon vrele(uppervp); 5562a31267eSMatthew Dillon if (upperdvp) 5572a31267eSMatthew Dillon vrele(upperdvp); 5582a31267eSMatthew Dillon *vpp = NULL; 559df8bae1dSRodney W. Grimes goto out; 560df8bae1dSRodney W. Grimes } 561df8bae1dSRodney W. Grimes 562df8bae1dSRodney W. Grimes MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), 563df8bae1dSRodney W. Grimes M_TEMP, M_WAITOK); 564df8bae1dSRodney W. Grimes 565996c772fSJohn Dyson (*vpp)->v_flag |= vflag; 566df8bae1dSRodney W. Grimes if (uppervp) 567df8bae1dSRodney W. Grimes (*vpp)->v_type = uppervp->v_type; 568df8bae1dSRodney W. Grimes else 569df8bae1dSRodney W. Grimes (*vpp)->v_type = lowervp->v_type; 5702a31267eSMatthew Dillon 571df8bae1dSRodney W. Grimes un = VTOUNION(*vpp); 5722a31267eSMatthew Dillon bzero(un, sizeof(*un)); 5732a31267eSMatthew Dillon 5742a31267eSMatthew Dillon lockinit(&un->un_lock, PVFS, "unlock", 0, 0); 5752a31267eSMatthew Dillon vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p); 5762a31267eSMatthew Dillon 577df8bae1dSRodney W. Grimes un->un_vnode = *vpp; 578df8bae1dSRodney W. Grimes un->un_uppervp = uppervp; 579996c772fSJohn Dyson un->un_uppersz = VNOVAL; 580df8bae1dSRodney W. Grimes un->un_lowervp = lowervp; 581996c772fSJohn Dyson un->un_lowersz = VNOVAL; 5822a31267eSMatthew Dillon un->un_dirvp = upperdvp; 5832a31267eSMatthew Dillon un->un_pvp = dvp; /* only parent dir in new allocation */ 5842a31267eSMatthew Dillon if (dvp != NULLVP) 5852a31267eSMatthew Dillon VREF(dvp); 586996c772fSJohn Dyson un->un_dircache = 0; 587df8bae1dSRodney W. Grimes un->un_openl = 0; 5882a31267eSMatthew Dillon 589996c772fSJohn Dyson if (cnp && (lowervp != NULLVP)) { 590df8bae1dSRodney W. Grimes un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); 591df8bae1dSRodney W. Grimes bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); 592df8bae1dSRodney W. Grimes un->un_path[cnp->cn_namelen] = '\0'; 593df8bae1dSRodney W. Grimes } else { 594df8bae1dSRodney W. Grimes un->un_path = 0; 5952a31267eSMatthew Dillon un->un_dirvp = NULL; 596df8bae1dSRodney W. Grimes } 597df8bae1dSRodney W. Grimes 598996c772fSJohn Dyson if (docache) { 599df8bae1dSRodney W. Grimes LIST_INSERT_HEAD(&unhead[hash], un, un_cache); 600996c772fSJohn Dyson un->un_flags |= UN_CACHED; 601996c772fSJohn Dyson } 602df8bae1dSRodney W. Grimes 6032a31267eSMatthew Dillon out: 604996c772fSJohn Dyson if (docache) 605df8bae1dSRodney W. Grimes union_list_unlock(hash); 606df8bae1dSRodney W. Grimes 607df8bae1dSRodney W. Grimes return (error); 608df8bae1dSRodney W. Grimes } 609df8bae1dSRodney W. Grimes 610df8bae1dSRodney W. Grimes int 611df8bae1dSRodney W. Grimes union_freevp(vp) 612df8bae1dSRodney W. Grimes struct vnode *vp; 613df8bae1dSRodney W. Grimes { 614df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(vp); 615df8bae1dSRodney W. Grimes 616996c772fSJohn Dyson if (un->un_flags & UN_CACHED) { 617996c772fSJohn Dyson un->un_flags &= ~UN_CACHED; 618df8bae1dSRodney W. Grimes LIST_REMOVE(un, un_cache); 619996c772fSJohn Dyson } 620df8bae1dSRodney W. Grimes 6212a31267eSMatthew Dillon if (un->un_pvp != NULLVP) { 622996c772fSJohn Dyson vrele(un->un_pvp); 6232a31267eSMatthew Dillon un->un_pvp = NULL; 6242a31267eSMatthew Dillon } 6252a31267eSMatthew Dillon if (un->un_uppervp != NULLVP) { 626df8bae1dSRodney W. Grimes vrele(un->un_uppervp); 6272a31267eSMatthew Dillon un->un_uppervp = NULL; 6282a31267eSMatthew Dillon } 6292a31267eSMatthew Dillon if (un->un_lowervp != NULLVP) { 630df8bae1dSRodney W. Grimes vrele(un->un_lowervp); 6312a31267eSMatthew Dillon un->un_lowervp = NULL; 6322a31267eSMatthew Dillon } 6332a31267eSMatthew Dillon if (un->un_dirvp != NULLVP) { 634df8bae1dSRodney W. Grimes vrele(un->un_dirvp); 6352a31267eSMatthew Dillon un->un_dirvp = NULL; 6362a31267eSMatthew Dillon } 6372a31267eSMatthew Dillon if (un->un_path) { 638df8bae1dSRodney W. Grimes free(un->un_path, M_TEMP); 6392a31267eSMatthew Dillon un->un_path = NULL; 6402a31267eSMatthew Dillon } 641a18b1f1dSJason Evans lockdestroy(&un->un_lock); 642df8bae1dSRodney W. Grimes 643df8bae1dSRodney W. Grimes FREE(vp->v_data, M_TEMP); 644df8bae1dSRodney W. Grimes vp->v_data = 0; 645df8bae1dSRodney W. Grimes 646df8bae1dSRodney W. Grimes return (0); 647df8bae1dSRodney W. Grimes } 648df8bae1dSRodney W. Grimes 649df8bae1dSRodney W. Grimes /* 650df8bae1dSRodney W. Grimes * copyfile. copy the vnode (fvp) to the vnode (tvp) 651df8bae1dSRodney W. Grimes * using a sequence of reads and writes. both (fvp) 652df8bae1dSRodney W. Grimes * and (tvp) are locked on entry and exit. 6532a31267eSMatthew Dillon * 6542a31267eSMatthew Dillon * fvp and tvp are both exclusive locked on call, but their refcount's 6552a31267eSMatthew Dillon * haven't been bumped at all. 656df8bae1dSRodney W. Grimes */ 65780b301c3SPoul-Henning Kamp static int 658996c772fSJohn Dyson union_copyfile(fvp, tvp, cred, p) 659df8bae1dSRodney W. Grimes struct vnode *fvp; 660df8bae1dSRodney W. Grimes struct vnode *tvp; 661996c772fSJohn Dyson struct ucred *cred; 662996c772fSJohn Dyson struct proc *p; 663df8bae1dSRodney W. Grimes { 664df8bae1dSRodney W. Grimes char *buf; 665df8bae1dSRodney W. Grimes struct uio uio; 666df8bae1dSRodney W. Grimes struct iovec iov; 667df8bae1dSRodney W. Grimes int error = 0; 668df8bae1dSRodney W. Grimes 669df8bae1dSRodney W. Grimes /* 670df8bae1dSRodney W. Grimes * strategy: 671df8bae1dSRodney W. Grimes * allocate a buffer of size MAXBSIZE. 672df8bae1dSRodney W. Grimes * loop doing reads and writes, keeping track 673df8bae1dSRodney W. Grimes * of the current uio offset. 674df8bae1dSRodney W. Grimes * give up at the first sign of trouble. 675df8bae1dSRodney W. Grimes */ 676df8bae1dSRodney W. Grimes 6772a31267eSMatthew Dillon bzero(&uio, sizeof(uio)); 6782a31267eSMatthew Dillon 679df8bae1dSRodney W. Grimes uio.uio_procp = p; 680df8bae1dSRodney W. Grimes uio.uio_segflg = UIO_SYSSPACE; 681df8bae1dSRodney W. Grimes uio.uio_offset = 0; 682df8bae1dSRodney W. Grimes 683996c772fSJohn Dyson VOP_LEASE(fvp, p, cred, LEASE_READ); 684996c772fSJohn Dyson VOP_LEASE(tvp, p, cred, LEASE_WRITE); 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); 687df8bae1dSRodney W. Grimes 688df8bae1dSRodney W. Grimes /* ugly loop follows... */ 689df8bae1dSRodney W. Grimes do { 690df8bae1dSRodney W. Grimes off_t offset = uio.uio_offset; 6912a31267eSMatthew Dillon int count; 6922a31267eSMatthew Dillon int bufoffset; 693df8bae1dSRodney W. Grimes 6942a31267eSMatthew Dillon /* 6952a31267eSMatthew Dillon * Setup for big read 6962a31267eSMatthew Dillon */ 697df8bae1dSRodney W. Grimes uio.uio_iov = &iov; 698df8bae1dSRodney W. Grimes uio.uio_iovcnt = 1; 699df8bae1dSRodney W. Grimes iov.iov_base = buf; 700df8bae1dSRodney W. Grimes iov.iov_len = MAXBSIZE; 701df8bae1dSRodney W. Grimes uio.uio_resid = iov.iov_len; 702df8bae1dSRodney W. Grimes uio.uio_rw = UIO_READ; 703df8bae1dSRodney W. Grimes 7042a31267eSMatthew Dillon if ((error = VOP_READ(fvp, &uio, 0, cred)) != 0) 7052a31267eSMatthew Dillon break; 7062a31267eSMatthew Dillon 7072a31267eSMatthew Dillon /* 7082a31267eSMatthew Dillon * Get bytes read, handle read eof case and setup for 7092a31267eSMatthew Dillon * write loop 7102a31267eSMatthew Dillon */ 7112a31267eSMatthew Dillon if ((count = MAXBSIZE - uio.uio_resid) == 0) 7122a31267eSMatthew Dillon break; 7132a31267eSMatthew Dillon bufoffset = 0; 7142a31267eSMatthew Dillon 7152a31267eSMatthew Dillon /* 7162a31267eSMatthew Dillon * Write until an error occurs or our buffer has been 7172a31267eSMatthew Dillon * exhausted, then update the offset for the next read. 7182a31267eSMatthew Dillon */ 7192a31267eSMatthew Dillon while (bufoffset < count) { 720df8bae1dSRodney W. Grimes uio.uio_iov = &iov; 721df8bae1dSRodney W. Grimes uio.uio_iovcnt = 1; 7222a31267eSMatthew Dillon iov.iov_base = buf + bufoffset; 7232a31267eSMatthew Dillon iov.iov_len = count - bufoffset; 7242a31267eSMatthew Dillon uio.uio_offset = offset + bufoffset; 725df8bae1dSRodney W. Grimes uio.uio_rw = UIO_WRITE; 726df8bae1dSRodney W. Grimes uio.uio_resid = iov.iov_len; 727df8bae1dSRodney W. Grimes 7282a31267eSMatthew Dillon if ((error = VOP_WRITE(tvp, &uio, 0, cred)) != 0) 729df8bae1dSRodney W. Grimes break; 7302a31267eSMatthew Dillon bufoffset += (count - bufoffset) - uio.uio_resid; 731df8bae1dSRodney W. Grimes } 7322a31267eSMatthew Dillon uio.uio_offset = offset + bufoffset; 733df8bae1dSRodney W. Grimes } while (error == 0); 734df8bae1dSRodney W. Grimes 735df8bae1dSRodney W. Grimes free(buf, M_TEMP); 736df8bae1dSRodney W. Grimes return (error); 737df8bae1dSRodney W. Grimes } 738df8bae1dSRodney W. Grimes 739df8bae1dSRodney W. Grimes /* 7402a31267eSMatthew Dillon * 7412a31267eSMatthew Dillon * un's vnode is assumed to be locked on entry and remains locked on exit. 742996c772fSJohn Dyson */ 7432a31267eSMatthew Dillon 744996c772fSJohn Dyson int 745996c772fSJohn Dyson union_copyup(un, docopy, cred, p) 746996c772fSJohn Dyson struct union_node *un; 747996c772fSJohn Dyson int docopy; 748996c772fSJohn Dyson struct ucred *cred; 749996c772fSJohn Dyson struct proc *p; 750996c772fSJohn Dyson { 751996c772fSJohn Dyson int error; 752f2a2857bSKirk McKusick struct mount *mp; 753996c772fSJohn Dyson struct vnode *lvp, *uvp; 754996c772fSJohn Dyson 7555842d4e5SKATO Takenori /* 7565842d4e5SKATO Takenori * If the user does not have read permission, the vnode should not 7575842d4e5SKATO Takenori * be copied to upper layer. 7585842d4e5SKATO Takenori */ 7595842d4e5SKATO Takenori vn_lock(un->un_lowervp, LK_EXCLUSIVE | LK_RETRY, p); 7605842d4e5SKATO Takenori error = VOP_ACCESS(un->un_lowervp, VREAD, cred, p); 7615842d4e5SKATO Takenori VOP_UNLOCK(un->un_lowervp, 0, p); 7625842d4e5SKATO Takenori if (error) 7635842d4e5SKATO Takenori return (error); 7645842d4e5SKATO Takenori 765f2a2857bSKirk McKusick if ((error = vn_start_write(un->un_dirvp, &mp, V_WAIT | PCATCH)) != 0) 766996c772fSJohn Dyson return (error); 767f2a2857bSKirk McKusick if ((error = union_vn_create(&uvp, un, p)) != 0) { 768f2a2857bSKirk McKusick vn_finished_write(mp); 769f2a2857bSKirk McKusick return (error); 770f2a2857bSKirk McKusick } 771996c772fSJohn Dyson 772996c772fSJohn Dyson lvp = un->un_lowervp; 773996c772fSJohn Dyson 7742a31267eSMatthew Dillon KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount)); 775996c772fSJohn Dyson if (docopy) { 776996c772fSJohn Dyson /* 777996c772fSJohn Dyson * XX - should not ignore errors 778996c772fSJohn Dyson * from VOP_CLOSE 779996c772fSJohn Dyson */ 780996c772fSJohn Dyson vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p); 781996c772fSJohn Dyson error = VOP_OPEN(lvp, FREAD, cred, p); 7822a31267eSMatthew Dillon if (error == 0 && vn_canvmio(lvp) == TRUE) 7832a31267eSMatthew Dillon error = vfs_object_create(lvp, p, cred); 784996c772fSJohn Dyson if (error == 0) { 785996c772fSJohn Dyson error = union_copyfile(lvp, uvp, cred, p); 786996c772fSJohn Dyson VOP_UNLOCK(lvp, 0, p); 787996c772fSJohn Dyson (void) VOP_CLOSE(lvp, FREAD, cred, p); 788996c772fSJohn Dyson } 789996c772fSJohn Dyson if (error == 0) 7902a31267eSMatthew Dillon UDEBUG(("union: copied up %s\n", un->un_path)); 791996c772fSJohn Dyson 792996c772fSJohn Dyson } 793996c772fSJohn Dyson VOP_UNLOCK(uvp, 0, p); 794f2a2857bSKirk McKusick vn_finished_write(mp); 7952a31267eSMatthew Dillon union_newupper(un, uvp); 7962a31267eSMatthew Dillon KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount)); 797996c772fSJohn Dyson union_vn_close(uvp, FWRITE, cred, p); 7982a31267eSMatthew Dillon KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount)); 799996c772fSJohn Dyson /* 800996c772fSJohn Dyson * Subsequent IOs will go to the top layer, so 801996c772fSJohn Dyson * call close on the lower vnode and open on the 802996c772fSJohn Dyson * upper vnode to ensure that the filesystem keeps 803996c772fSJohn Dyson * its references counts right. This doesn't do 804996c772fSJohn Dyson * the right thing with (cred) and (FREAD) though. 805996c772fSJohn Dyson * Ignoring error returns is not right, either. 806996c772fSJohn Dyson */ 807996c772fSJohn Dyson if (error == 0) { 808996c772fSJohn Dyson int i; 809996c772fSJohn Dyson 810996c772fSJohn Dyson for (i = 0; i < un->un_openl; i++) { 811996c772fSJohn Dyson (void) VOP_CLOSE(lvp, FREAD, cred, p); 812996c772fSJohn Dyson (void) VOP_OPEN(uvp, FREAD, cred, p); 813996c772fSJohn Dyson } 814e3a285c7SMatthew Dillon if (un->un_openl) { 8152a31267eSMatthew Dillon if (vn_canvmio(uvp) == TRUE) 8162a31267eSMatthew Dillon error = vfs_object_create(uvp, p, cred); 817e3a285c7SMatthew Dillon } 818996c772fSJohn Dyson un->un_openl = 0; 819996c772fSJohn Dyson } 820996c772fSJohn Dyson 821996c772fSJohn Dyson return (error); 822996c772fSJohn Dyson 823996c772fSJohn Dyson } 824996c772fSJohn Dyson 8252a31267eSMatthew Dillon /* 8262a31267eSMatthew Dillon * union_relookup: 8272a31267eSMatthew Dillon * 8282a31267eSMatthew Dillon * dvp should be locked on entry and will be locked on return. No 8292a31267eSMatthew Dillon * net change in the ref count will occur. 8302a31267eSMatthew Dillon * 8312a31267eSMatthew Dillon * If an error is returned, *vpp will be invalid, otherwise it 8322a31267eSMatthew Dillon * will hold a locked, referenced vnode. If *vpp == dvp then 8332a31267eSMatthew Dillon * remember that only one exclusive lock is held. 8342a31267eSMatthew Dillon */ 8352a31267eSMatthew Dillon 836996c772fSJohn Dyson static int 837996c772fSJohn Dyson union_relookup(um, dvp, vpp, cnp, cn, path, pathlen) 838996c772fSJohn Dyson struct union_mount *um; 839996c772fSJohn Dyson struct vnode *dvp; 840996c772fSJohn Dyson struct vnode **vpp; 841996c772fSJohn Dyson struct componentname *cnp; 842996c772fSJohn Dyson struct componentname *cn; 843996c772fSJohn Dyson char *path; 844996c772fSJohn Dyson int pathlen; 845996c772fSJohn Dyson { 846996c772fSJohn Dyson int error; 847996c772fSJohn Dyson 848996c772fSJohn Dyson /* 849996c772fSJohn Dyson * A new componentname structure must be faked up because 850996c772fSJohn Dyson * there is no way to know where the upper level cnp came 851996c772fSJohn Dyson * from or what it is being used for. This must duplicate 852996c772fSJohn Dyson * some of the work done by NDINIT, some of the work done 853996c772fSJohn Dyson * by namei, some of the work done by lookup and some of 854996c772fSJohn Dyson * the work done by VOP_LOOKUP when given a CREATE flag. 855996c772fSJohn Dyson * Conclusion: Horrible. 856996c772fSJohn Dyson */ 857996c772fSJohn Dyson cn->cn_namelen = pathlen; 85899448ed1SJohn Dyson cn->cn_pnbuf = zalloc(namei_zone); 859996c772fSJohn Dyson bcopy(path, cn->cn_pnbuf, cn->cn_namelen); 860996c772fSJohn Dyson cn->cn_pnbuf[cn->cn_namelen] = '\0'; 861996c772fSJohn Dyson 862996c772fSJohn Dyson cn->cn_nameiop = CREATE; 8632a31267eSMatthew Dillon cn->cn_flags = (LOCKPARENT|LOCKLEAF|HASBUF|SAVENAME|ISLASTCN); 864996c772fSJohn Dyson cn->cn_proc = cnp->cn_proc; 865996c772fSJohn Dyson if (um->um_op == UNMNT_ABOVE) 866996c772fSJohn Dyson cn->cn_cred = cnp->cn_cred; 867996c772fSJohn Dyson else 868996c772fSJohn Dyson cn->cn_cred = um->um_cred; 869996c772fSJohn Dyson cn->cn_nameptr = cn->cn_pnbuf; 870996c772fSJohn Dyson cn->cn_consume = cnp->cn_consume; 871996c772fSJohn Dyson 872996c772fSJohn Dyson VREF(dvp); 8732a31267eSMatthew Dillon VOP_UNLOCK(dvp, 0, cnp->cn_proc); 8742a31267eSMatthew Dillon 8752a31267eSMatthew Dillon /* 8762a31267eSMatthew Dillon * Pass dvp unlocked and referenced on call to relookup(). 8772a31267eSMatthew Dillon * 8782a31267eSMatthew Dillon * If an error occurs, dvp will be returned unlocked and dereferenced. 8792a31267eSMatthew Dillon */ 8802a31267eSMatthew Dillon 8812a31267eSMatthew Dillon if ((error = relookup(dvp, vpp, cn)) != 0) { 8822a31267eSMatthew Dillon vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc); 8832a31267eSMatthew Dillon return(error); 884b422956cSPoul-Henning Kamp } 885996c772fSJohn Dyson 8862a31267eSMatthew Dillon /* 8872a31267eSMatthew Dillon * If no error occurs, dvp will be returned locked with the reference 8882a31267eSMatthew Dillon * left as before, and vpp will be returned referenced and locked. 8892a31267eSMatthew Dillon * 8902a31267eSMatthew Dillon * We want to return with dvp as it was passed to us, so we get 8912a31267eSMatthew Dillon * rid of our reference. 8922a31267eSMatthew Dillon */ 8932a31267eSMatthew Dillon vrele(dvp); 8942a31267eSMatthew Dillon return (0); 895996c772fSJohn Dyson } 896996c772fSJohn Dyson 897996c772fSJohn Dyson /* 898df8bae1dSRodney W. Grimes * Create a shadow directory in the upper layer. 899df8bae1dSRodney W. Grimes * The new vnode is returned locked. 900df8bae1dSRodney W. Grimes * 901df8bae1dSRodney W. Grimes * (um) points to the union mount structure for access to the 902df8bae1dSRodney W. Grimes * the mounting process's credentials. 9032a31267eSMatthew Dillon * (dvp) is the directory in which to create the shadow directory, 9042a31267eSMatthew Dillon * it is locked (but not ref'd) on entry and return. 905df8bae1dSRodney W. Grimes * (cnp) is the componentname to be created. 906df8bae1dSRodney W. Grimes * (vpp) is the returned newly created shadow directory, which 9072a31267eSMatthew Dillon * is returned locked and ref'd 908df8bae1dSRodney W. Grimes */ 909df8bae1dSRodney W. Grimes int 910df8bae1dSRodney W. Grimes union_mkshadow(um, dvp, cnp, vpp) 911df8bae1dSRodney W. Grimes struct union_mount *um; 912df8bae1dSRodney W. Grimes struct vnode *dvp; 913df8bae1dSRodney W. Grimes struct componentname *cnp; 914df8bae1dSRodney W. Grimes struct vnode **vpp; 915df8bae1dSRodney W. Grimes { 916df8bae1dSRodney W. Grimes int error; 917df8bae1dSRodney W. Grimes struct vattr va; 918df8bae1dSRodney W. Grimes struct proc *p = cnp->cn_proc; 919df8bae1dSRodney W. Grimes struct componentname cn; 920f2a2857bSKirk McKusick struct mount *mp; 921df8bae1dSRodney W. Grimes 922f2a2857bSKirk McKusick if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)) != 0) 923996c772fSJohn Dyson return (error); 924f2a2857bSKirk McKusick if ((error = union_relookup(um, dvp, vpp, cnp, &cn, 925f2a2857bSKirk McKusick cnp->cn_nameptr, cnp->cn_namelen)) != 0) { 926f2a2857bSKirk McKusick vn_finished_write(mp); 927f2a2857bSKirk McKusick return (error); 928f2a2857bSKirk McKusick } 929996c772fSJohn Dyson 930996c772fSJohn Dyson if (*vpp) { 931762e6b85SEivind Eklund if (cn.cn_flags & HASBUF) { 932762e6b85SEivind Eklund zfree(namei_zone, cn.cn_pnbuf); 933762e6b85SEivind Eklund cn.cn_flags &= ~HASBUF; 934762e6b85SEivind Eklund } 9352a31267eSMatthew Dillon if (dvp == *vpp) 936996c772fSJohn Dyson vrele(*vpp); 9372a31267eSMatthew Dillon else 9382a31267eSMatthew Dillon vput(*vpp); 939f2a2857bSKirk McKusick vn_finished_write(mp); 940996c772fSJohn Dyson *vpp = NULLVP; 941996c772fSJohn Dyson return (EEXIST); 942996c772fSJohn Dyson } 943996c772fSJohn Dyson 944df8bae1dSRodney W. Grimes /* 945df8bae1dSRodney W. Grimes * policy: when creating the shadow directory in the 946df8bae1dSRodney W. Grimes * upper layer, create it owned by the user who did 947df8bae1dSRodney W. Grimes * the mount, group from parent directory, and mode 948df8bae1dSRodney W. Grimes * 777 modified by umask (ie mostly identical to the 949df8bae1dSRodney W. Grimes * mkdir syscall). (jsp, kb) 950df8bae1dSRodney W. Grimes */ 951df8bae1dSRodney W. Grimes 952df8bae1dSRodney W. Grimes VATTR_NULL(&va); 953df8bae1dSRodney W. Grimes va.va_type = VDIR; 954df8bae1dSRodney W. Grimes va.va_mode = um->um_cmode; 955df8bae1dSRodney W. Grimes 956996c772fSJohn Dyson /* VOP_LEASE: dvp is locked */ 957996c772fSJohn Dyson VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE); 958df8bae1dSRodney W. Grimes 959df8bae1dSRodney W. Grimes error = VOP_MKDIR(dvp, vpp, &cn, &va); 960762e6b85SEivind Eklund if (cn.cn_flags & HASBUF) { 961762e6b85SEivind Eklund zfree(namei_zone, cn.cn_pnbuf); 962762e6b85SEivind Eklund cn.cn_flags &= ~HASBUF; 963762e6b85SEivind Eklund } 9642a31267eSMatthew Dillon /*vput(dvp);*/ 965f2a2857bSKirk McKusick vn_finished_write(mp); 966df8bae1dSRodney W. Grimes return (error); 967df8bae1dSRodney W. Grimes } 968df8bae1dSRodney W. Grimes 969df8bae1dSRodney W. Grimes /* 970996c772fSJohn Dyson * Create a whiteout entry in the upper layer. 971996c772fSJohn Dyson * 972996c772fSJohn Dyson * (um) points to the union mount structure for access to the 973996c772fSJohn Dyson * the mounting process's credentials. 974996c772fSJohn Dyson * (dvp) is the directory in which to create the whiteout. 9752a31267eSMatthew Dillon * it is locked on entry and return. 976996c772fSJohn Dyson * (cnp) is the componentname to be created. 977996c772fSJohn Dyson */ 978996c772fSJohn Dyson int 979996c772fSJohn Dyson union_mkwhiteout(um, dvp, cnp, path) 980996c772fSJohn Dyson struct union_mount *um; 981996c772fSJohn Dyson struct vnode *dvp; 982996c772fSJohn Dyson struct componentname *cnp; 983996c772fSJohn Dyson char *path; 984996c772fSJohn Dyson { 985996c772fSJohn Dyson int error; 986996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 987996c772fSJohn Dyson struct vnode *wvp; 988996c772fSJohn Dyson struct componentname cn; 989f2a2857bSKirk McKusick struct mount *mp; 990996c772fSJohn Dyson 991f2a2857bSKirk McKusick if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)) != 0) 992996c772fSJohn Dyson return (error); 993f2a2857bSKirk McKusick error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); 994f2a2857bSKirk McKusick if (error) { 995f2a2857bSKirk McKusick vn_finished_write(mp); 996f2a2857bSKirk McKusick return (error); 997f2a2857bSKirk McKusick } 998996c772fSJohn Dyson 999996c772fSJohn Dyson if (wvp) { 1000762e6b85SEivind Eklund if (cn.cn_flags & HASBUF) { 1001762e6b85SEivind Eklund zfree(namei_zone, cn.cn_pnbuf); 1002762e6b85SEivind Eklund cn.cn_flags &= ~HASBUF; 1003762e6b85SEivind Eklund } 10042a31267eSMatthew Dillon if (wvp == dvp) 1005996c772fSJohn Dyson vrele(wvp); 10062a31267eSMatthew Dillon else 10072a31267eSMatthew Dillon vput(wvp); 1008f2a2857bSKirk McKusick vn_finished_write(mp); 1009996c772fSJohn Dyson return (EEXIST); 1010996c772fSJohn Dyson } 1011996c772fSJohn Dyson 1012996c772fSJohn Dyson /* VOP_LEASE: dvp is locked */ 1013996c772fSJohn Dyson VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE); 1014996c772fSJohn Dyson 1015996c772fSJohn Dyson error = VOP_WHITEOUT(dvp, &cn, CREATE); 1016762e6b85SEivind Eklund if (cn.cn_flags & HASBUF) { 1017762e6b85SEivind Eklund zfree(namei_zone, cn.cn_pnbuf); 1018762e6b85SEivind Eklund cn.cn_flags &= ~HASBUF; 1019762e6b85SEivind Eklund } 1020f2a2857bSKirk McKusick vn_finished_write(mp); 1021996c772fSJohn Dyson return (error); 1022996c772fSJohn Dyson } 1023996c772fSJohn Dyson 1024996c772fSJohn Dyson /* 1025df8bae1dSRodney W. Grimes * union_vn_create: creates and opens a new shadow file 1026df8bae1dSRodney W. Grimes * on the upper union layer. this function is similar 1027df8bae1dSRodney W. Grimes * in spirit to calling vn_open but it avoids calling namei(). 1028df8bae1dSRodney W. Grimes * the problem with calling namei is that a) it locks too many 1029df8bae1dSRodney W. Grimes * things, and b) it doesn't start at the "right" directory, 1030df8bae1dSRodney W. Grimes * whereas relookup is told where to start. 10312a31267eSMatthew Dillon * 10322a31267eSMatthew Dillon * On entry, the vnode associated with un is locked. It remains locked 10332a31267eSMatthew Dillon * on return. 10342a31267eSMatthew Dillon * 10352a31267eSMatthew Dillon * If no error occurs, *vpp contains a locked referenced vnode for your 10362a31267eSMatthew Dillon * use. If an error occurs *vpp iis undefined. 1037df8bae1dSRodney W. Grimes */ 103880b301c3SPoul-Henning Kamp static int 1039df8bae1dSRodney W. Grimes union_vn_create(vpp, un, p) 1040df8bae1dSRodney W. Grimes struct vnode **vpp; 1041df8bae1dSRodney W. Grimes struct union_node *un; 1042df8bae1dSRodney W. Grimes struct proc *p; 1043df8bae1dSRodney W. Grimes { 1044df8bae1dSRodney W. Grimes struct vnode *vp; 1045df8bae1dSRodney W. Grimes struct ucred *cred = p->p_ucred; 1046df8bae1dSRodney W. Grimes struct vattr vat; 1047df8bae1dSRodney W. Grimes struct vattr *vap = &vat; 1048df8bae1dSRodney W. Grimes int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL); 1049df8bae1dSRodney W. Grimes int error; 1050df8bae1dSRodney W. Grimes int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask; 1051df8bae1dSRodney W. Grimes struct componentname cn; 1052df8bae1dSRodney W. Grimes 1053df8bae1dSRodney W. Grimes *vpp = NULLVP; 1054df8bae1dSRodney W. Grimes 1055df8bae1dSRodney W. Grimes /* 1056df8bae1dSRodney W. Grimes * Build a new componentname structure (for the same 1057df8bae1dSRodney W. Grimes * reasons outlines in union_mkshadow). 1058df8bae1dSRodney W. Grimes * The difference here is that the file is owned by 1059df8bae1dSRodney W. Grimes * the current user, rather than by the person who 1060df8bae1dSRodney W. Grimes * did the mount, since the current user needs to be 1061df8bae1dSRodney W. Grimes * able to write the file (that's why it is being 1062df8bae1dSRodney W. Grimes * copied in the first place). 1063df8bae1dSRodney W. Grimes */ 1064df8bae1dSRodney W. Grimes cn.cn_namelen = strlen(un->un_path); 106599448ed1SJohn Dyson cn.cn_pnbuf = zalloc(namei_zone); 1066df8bae1dSRodney W. Grimes bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1); 1067df8bae1dSRodney W. Grimes cn.cn_nameiop = CREATE; 10682a31267eSMatthew Dillon cn.cn_flags = (LOCKPARENT|LOCKLEAF|HASBUF|SAVENAME|ISLASTCN); 1069df8bae1dSRodney W. Grimes cn.cn_proc = p; 1070df8bae1dSRodney W. Grimes cn.cn_cred = p->p_ucred; 1071df8bae1dSRodney W. Grimes cn.cn_nameptr = cn.cn_pnbuf; 1072df8bae1dSRodney W. Grimes cn.cn_consume = 0; 1073df8bae1dSRodney W. Grimes 10742a31267eSMatthew Dillon /* 10752a31267eSMatthew Dillon * Pass dvp unlocked and referenced on call to relookup(). 10762a31267eSMatthew Dillon * 10772a31267eSMatthew Dillon * If an error occurs, dvp will be returned unlocked and dereferenced. 10782a31267eSMatthew Dillon */ 1079df8bae1dSRodney W. Grimes VREF(un->un_dirvp); 10803a773ad0SPoul-Henning Kamp error = relookup(un->un_dirvp, &vp, &cn); 10813a773ad0SPoul-Henning Kamp if (error) 1082df8bae1dSRodney W. Grimes return (error); 1083df8bae1dSRodney W. Grimes 10842a31267eSMatthew Dillon /* 10852a31267eSMatthew Dillon * If no error occurs, dvp will be returned locked with the reference 10862a31267eSMatthew Dillon * left as before, and vpp will be returned referenced and locked. 10872a31267eSMatthew Dillon */ 1088df8bae1dSRodney W. Grimes if (vp) { 1089df8bae1dSRodney W. Grimes vput(un->un_dirvp); 1090762e6b85SEivind Eklund if (cn.cn_flags & HASBUF) { 1091762e6b85SEivind Eklund zfree(namei_zone, cn.cn_pnbuf); 1092762e6b85SEivind Eklund cn.cn_flags &= ~HASBUF; 1093762e6b85SEivind Eklund } 10942a31267eSMatthew Dillon if (vp == un->un_dirvp) 1095df8bae1dSRodney W. Grimes vrele(vp); 10962a31267eSMatthew Dillon else 10972a31267eSMatthew Dillon vput(vp); 1098df8bae1dSRodney W. Grimes return (EEXIST); 1099df8bae1dSRodney W. Grimes } 1100df8bae1dSRodney W. Grimes 1101df8bae1dSRodney W. Grimes /* 1102df8bae1dSRodney W. Grimes * Good - there was no race to create the file 1103df8bae1dSRodney W. Grimes * so go ahead and create it. The permissions 1104df8bae1dSRodney W. Grimes * on the file will be 0666 modified by the 1105df8bae1dSRodney W. Grimes * current user's umask. Access to the file, while 1106df8bae1dSRodney W. Grimes * it is unioned, will require access to the top *and* 1107df8bae1dSRodney W. Grimes * bottom files. Access when not unioned will simply 1108df8bae1dSRodney W. Grimes * require access to the top-level file. 1109df8bae1dSRodney W. Grimes * TODO: confirm choice of access permissions. 1110df8bae1dSRodney W. Grimes */ 1111df8bae1dSRodney W. Grimes VATTR_NULL(vap); 1112df8bae1dSRodney W. Grimes vap->va_type = VREG; 1113df8bae1dSRodney W. Grimes vap->va_mode = cmode; 1114996c772fSJohn Dyson VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE); 11157be2d300SMike Smith error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap); 1116762e6b85SEivind Eklund if (cn.cn_flags & HASBUF) { 1117762e6b85SEivind Eklund zfree(namei_zone, cn.cn_pnbuf); 1118762e6b85SEivind Eklund cn.cn_flags &= ~HASBUF; 1119762e6b85SEivind Eklund } 11207be2d300SMike Smith vput(un->un_dirvp); 11217be2d300SMike Smith if (error) 1122df8bae1dSRodney W. Grimes return (error); 1123df8bae1dSRodney W. Grimes 11243a773ad0SPoul-Henning Kamp error = VOP_OPEN(vp, fmode, cred, p); 11252a31267eSMatthew Dillon if (error == 0 && vn_canvmio(vp) == TRUE) 11262a31267eSMatthew Dillon error = vfs_object_create(vp, p, cred); 11273a773ad0SPoul-Henning Kamp if (error) { 1128df8bae1dSRodney W. Grimes vput(vp); 1129df8bae1dSRodney W. Grimes return (error); 1130df8bae1dSRodney W. Grimes } 1131df8bae1dSRodney W. Grimes vp->v_writecount++; 1132df8bae1dSRodney W. Grimes *vpp = vp; 1133df8bae1dSRodney W. Grimes return (0); 1134df8bae1dSRodney W. Grimes } 1135df8bae1dSRodney W. Grimes 113680b301c3SPoul-Henning Kamp static int 1137df8bae1dSRodney W. Grimes union_vn_close(vp, fmode, cred, p) 1138df8bae1dSRodney W. Grimes struct vnode *vp; 1139df8bae1dSRodney W. Grimes int fmode; 1140df8bae1dSRodney W. Grimes struct ucred *cred; 1141df8bae1dSRodney W. Grimes struct proc *p; 1142df8bae1dSRodney W. Grimes { 1143996c772fSJohn Dyson 1144df8bae1dSRodney W. Grimes if (fmode & FWRITE) 1145df8bae1dSRodney W. Grimes --vp->v_writecount; 1146cf2455a3SBruce Evans return (VOP_CLOSE(vp, fmode, cred, p)); 1147df8bae1dSRodney W. Grimes } 1148df8bae1dSRodney W. Grimes 11492a31267eSMatthew Dillon #if 0 11502a31267eSMatthew Dillon 11512a31267eSMatthew Dillon /* 11522a31267eSMatthew Dillon * union_removed_upper: 11532a31267eSMatthew Dillon * 11542a31267eSMatthew Dillon * called with union_node unlocked. XXX 11552a31267eSMatthew Dillon */ 11562a31267eSMatthew Dillon 1157df8bae1dSRodney W. Grimes void 1158df8bae1dSRodney W. Grimes union_removed_upper(un) 1159df8bae1dSRodney W. Grimes struct union_node *un; 1160df8bae1dSRodney W. Grimes { 1161996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1162b69aa7f1SKATO Takenori struct vnode **vpp; 1163df8bae1dSRodney W. Grimes 1164b69aa7f1SKATO Takenori /* 1165b69aa7f1SKATO Takenori * Do not set the uppervp to NULLVP. If lowervp is NULLVP, 11669758931dSKATO Takenori * union node will have neither uppervp nor lowervp. We remove 1167b69aa7f1SKATO Takenori * the union node from cache, so that it will not be referrenced. 1168b69aa7f1SKATO Takenori */ 1169df8bae1dSRodney W. Grimes union_newupper(un, NULLVP); 1170b69aa7f1SKATO Takenori if (un->un_dircache != 0) { 1171b69aa7f1SKATO Takenori for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) 1172b69aa7f1SKATO Takenori vrele(*vpp); 1173b69aa7f1SKATO Takenori free(un->un_dircache, M_TEMP); 1174b69aa7f1SKATO Takenori un->un_dircache = 0; 1175b69aa7f1SKATO Takenori } 1176b69aa7f1SKATO Takenori 1177996c772fSJohn Dyson if (un->un_flags & UN_CACHED) { 1178996c772fSJohn Dyson un->un_flags &= ~UN_CACHED; 1179996c772fSJohn Dyson LIST_REMOVE(un, un_cache); 1180df8bae1dSRodney W. Grimes } 1181996c772fSJohn Dyson } 1182996c772fSJohn Dyson 1183996c772fSJohn Dyson #endif 1184996c772fSJohn Dyson 1185996c772fSJohn Dyson /* 1186996c772fSJohn Dyson * determine whether a whiteout is needed 1187996c772fSJohn Dyson * during a remove/rmdir operation. 1188996c772fSJohn Dyson */ 1189996c772fSJohn Dyson int 1190996c772fSJohn Dyson union_dowhiteout(un, cred, p) 1191996c772fSJohn Dyson struct union_node *un; 1192996c772fSJohn Dyson struct ucred *cred; 1193996c772fSJohn Dyson struct proc *p; 1194996c772fSJohn Dyson { 1195996c772fSJohn Dyson struct vattr va; 1196996c772fSJohn Dyson 1197996c772fSJohn Dyson if (un->un_lowervp != NULLVP) 1198996c772fSJohn Dyson return (1); 1199996c772fSJohn Dyson 1200996c772fSJohn Dyson if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 && 1201996c772fSJohn Dyson (va.va_flags & OPAQUE)) 1202996c772fSJohn Dyson return (1); 1203996c772fSJohn Dyson 1204996c772fSJohn Dyson return (0); 1205996c772fSJohn Dyson } 1206996c772fSJohn Dyson 1207996c772fSJohn Dyson static void 1208996c772fSJohn Dyson union_dircache_r(vp, vppp, cntp) 1209996c772fSJohn Dyson struct vnode *vp; 1210996c772fSJohn Dyson struct vnode ***vppp; 1211996c772fSJohn Dyson int *cntp; 1212996c772fSJohn Dyson { 1213996c772fSJohn Dyson struct union_node *un; 1214996c772fSJohn Dyson 1215996c772fSJohn Dyson if (vp->v_op != union_vnodeop_p) { 1216996c772fSJohn Dyson if (vppp) { 1217996c772fSJohn Dyson VREF(vp); 1218996c772fSJohn Dyson *(*vppp)++ = vp; 1219996c772fSJohn Dyson if (--(*cntp) == 0) 1220996c772fSJohn Dyson panic("union: dircache table too small"); 1221996c772fSJohn Dyson } else { 1222996c772fSJohn Dyson (*cntp)++; 1223996c772fSJohn Dyson } 1224996c772fSJohn Dyson 1225996c772fSJohn Dyson return; 1226996c772fSJohn Dyson } 1227996c772fSJohn Dyson 1228996c772fSJohn Dyson un = VTOUNION(vp); 1229996c772fSJohn Dyson if (un->un_uppervp != NULLVP) 1230996c772fSJohn Dyson union_dircache_r(un->un_uppervp, vppp, cntp); 1231996c772fSJohn Dyson if (un->un_lowervp != NULLVP) 1232996c772fSJohn Dyson union_dircache_r(un->un_lowervp, vppp, cntp); 1233996c772fSJohn Dyson } 1234996c772fSJohn Dyson 1235996c772fSJohn Dyson struct vnode * 1236996c772fSJohn Dyson union_dircache(vp, p) 1237996c772fSJohn Dyson struct vnode *vp; 1238996c772fSJohn Dyson struct proc *p; 1239996c772fSJohn Dyson { 1240996c772fSJohn Dyson int cnt; 1241996c772fSJohn Dyson struct vnode *nvp; 1242996c772fSJohn Dyson struct vnode **vpp; 1243996c772fSJohn Dyson struct vnode **dircache; 1244996c772fSJohn Dyson struct union_node *un; 1245996c772fSJohn Dyson int error; 1246996c772fSJohn Dyson 1247996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1248996c772fSJohn Dyson dircache = VTOUNION(vp)->un_dircache; 1249996c772fSJohn Dyson 1250996c772fSJohn Dyson nvp = NULLVP; 1251996c772fSJohn Dyson 12522a31267eSMatthew Dillon if (dircache == NULL) { 1253996c772fSJohn Dyson cnt = 0; 1254996c772fSJohn Dyson union_dircache_r(vp, 0, &cnt); 1255996c772fSJohn Dyson cnt++; 12562a31267eSMatthew Dillon dircache = malloc(cnt * sizeof(struct vnode *), 1257996c772fSJohn Dyson M_TEMP, M_WAITOK); 1258996c772fSJohn Dyson vpp = dircache; 1259996c772fSJohn Dyson union_dircache_r(vp, &vpp, &cnt); 1260996c772fSJohn Dyson *vpp = NULLVP; 1261996c772fSJohn Dyson vpp = dircache + 1; 1262996c772fSJohn Dyson } else { 1263996c772fSJohn Dyson vpp = dircache; 1264996c772fSJohn Dyson do { 1265996c772fSJohn Dyson if (*vpp++ == VTOUNION(vp)->un_uppervp) 1266996c772fSJohn Dyson break; 1267996c772fSJohn Dyson } while (*vpp != NULLVP); 1268996c772fSJohn Dyson } 1269996c772fSJohn Dyson 1270996c772fSJohn Dyson if (*vpp == NULLVP) 1271996c772fSJohn Dyson goto out; 1272996c772fSJohn Dyson 12732a31267eSMatthew Dillon /*vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p);*/ 12742a31267eSMatthew Dillon UDEBUG(("ALLOCVP-3 %p ref %d\n", *vpp, (*vpp ? (*vpp)->v_usecount : -99))); 1275996c772fSJohn Dyson VREF(*vpp); 12762a31267eSMatthew Dillon error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, NULL, *vpp, NULLVP, 0); 12772a31267eSMatthew Dillon UDEBUG(("ALLOCVP-3B %p ref %d\n", nvp, (*vpp ? (*vpp)->v_usecount : -99))); 1278996c772fSJohn Dyson if (error) 1279996c772fSJohn Dyson goto out; 1280996c772fSJohn Dyson 1281996c772fSJohn Dyson VTOUNION(vp)->un_dircache = 0; 1282996c772fSJohn Dyson un = VTOUNION(nvp); 1283996c772fSJohn Dyson un->un_dircache = dircache; 1284996c772fSJohn Dyson 1285996c772fSJohn Dyson out: 1286996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1287996c772fSJohn Dyson return (nvp); 1288df8bae1dSRodney W. Grimes } 12898c14bf40SPeter Wemm 12908c14bf40SPeter Wemm /* 12918c14bf40SPeter Wemm * Module glue to remove #ifdef UNION from vfs_syscalls.c 12928c14bf40SPeter Wemm */ 12938c14bf40SPeter Wemm static int 12948c14bf40SPeter Wemm union_dircheck(struct proc *p, struct vnode **vp, struct file *fp) 12958c14bf40SPeter Wemm { 12968c14bf40SPeter Wemm int error = 0; 12978c14bf40SPeter Wemm 12988c14bf40SPeter Wemm if ((*vp)->v_op == union_vnodeop_p) { 12998c14bf40SPeter Wemm struct vnode *lvp; 13008c14bf40SPeter Wemm 13018c14bf40SPeter Wemm lvp = union_dircache(*vp, p); 13028c14bf40SPeter Wemm if (lvp != NULLVP) { 13038c14bf40SPeter Wemm struct vattr va; 13048c14bf40SPeter Wemm 13058c14bf40SPeter Wemm /* 13068c14bf40SPeter Wemm * If the directory is opaque, 13078c14bf40SPeter Wemm * then don't show lower entries 13088c14bf40SPeter Wemm */ 13098c14bf40SPeter Wemm error = VOP_GETATTR(*vp, &va, fp->f_cred, p); 13108c14bf40SPeter Wemm if (va.va_flags & OPAQUE) { 13118c14bf40SPeter Wemm vput(lvp); 13128c14bf40SPeter Wemm lvp = NULL; 13138c14bf40SPeter Wemm } 13148c14bf40SPeter Wemm } 13158c14bf40SPeter Wemm 13168c14bf40SPeter Wemm if (lvp != NULLVP) { 13178c14bf40SPeter Wemm error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 13182a31267eSMatthew Dillon if (error == 0 && vn_canvmio(lvp) == TRUE) 13192a31267eSMatthew Dillon error = vfs_object_create(lvp, p, fp->f_cred); 13208c14bf40SPeter Wemm if (error) { 13218c14bf40SPeter Wemm vput(lvp); 13228c14bf40SPeter Wemm return (error); 13238c14bf40SPeter Wemm } 13248c14bf40SPeter Wemm VOP_UNLOCK(lvp, 0, p); 13258c14bf40SPeter Wemm fp->f_data = (caddr_t) lvp; 13268c14bf40SPeter Wemm fp->f_offset = 0; 13278c14bf40SPeter Wemm error = vn_close(*vp, FREAD, fp->f_cred, p); 13288c14bf40SPeter Wemm if (error) 13298c14bf40SPeter Wemm return (error); 13308c14bf40SPeter Wemm *vp = lvp; 13318c14bf40SPeter Wemm return -1; /* goto unionread */ 13328c14bf40SPeter Wemm } 13338c14bf40SPeter Wemm } 13348c14bf40SPeter Wemm return error; 13358c14bf40SPeter Wemm } 13368c14bf40SPeter Wemm 1337c25ded31SBruce Evans static int 1338c25ded31SBruce Evans union_modevent(module_t mod, int type, void *data) 13398c14bf40SPeter Wemm { 13408c14bf40SPeter Wemm switch (type) { 13418c14bf40SPeter Wemm case MOD_LOAD: 13428c14bf40SPeter Wemm union_dircheckp = union_dircheck; 13438c14bf40SPeter Wemm break; 13448c14bf40SPeter Wemm case MOD_UNLOAD: 13458c14bf40SPeter Wemm union_dircheckp = NULL; 13468c14bf40SPeter Wemm break; 13478c14bf40SPeter Wemm default: 13488c14bf40SPeter Wemm break; 13498c14bf40SPeter Wemm } 13508c14bf40SPeter Wemm return 0; 13518c14bf40SPeter Wemm } 13522a31267eSMatthew Dillon 13538c14bf40SPeter Wemm static moduledata_t union_mod = { 13548c14bf40SPeter Wemm "union_dircheck", 13558c14bf40SPeter Wemm union_modevent, 13568c14bf40SPeter Wemm NULL 13578c14bf40SPeter Wemm }; 13582a31267eSMatthew Dillon 13598c14bf40SPeter Wemm DECLARE_MODULE(union_dircheck, union_mod, SI_SUB_VFS, SI_ORDER_ANY); 1360