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> 438c14bf40SPeter Wemm #include <sys/kernel.h> 44df8bae1dSRodney W. Grimes #include <sys/vnode.h> 45df8bae1dSRodney W. Grimes #include <sys/namei.h> 46df8bae1dSRodney W. Grimes #include <sys/malloc.h> 473ac4d1efSBruce Evans #include <sys/fcntl.h> 488c14bf40SPeter Wemm #include <sys/file.h> 49df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 508c14bf40SPeter Wemm #include <sys/module.h> 51996c772fSJohn Dyson #include <sys/mount.h> 52996c772fSJohn Dyson #include <sys/stat.h> 53724ab195SMike Pritchard #include <vm/vm.h> 54724ab195SMike Pritchard #include <vm/vm_extern.h> /* for vnode_pager_setsize */ 55675ea6f0SBruce Evans #include <vm/vm_zone.h> 562a31267eSMatthew Dillon #include <vm/vm_object.h> /* for vm cache coherency */ 57df8bae1dSRodney W. Grimes #include <miscfs/union/union.h> 58df8bae1dSRodney W. Grimes 59df8bae1dSRodney W. Grimes #include <sys/proc.h> 60df8bae1dSRodney W. Grimes 619b5e8b3aSBruce Evans extern int union_init __P((void)); 629b5e8b3aSBruce Evans 63df8bae1dSRodney W. Grimes /* must be power of two, otherwise change UNION_HASH() */ 64df8bae1dSRodney W. Grimes #define NHASH 32 65df8bae1dSRodney W. Grimes 66df8bae1dSRodney W. Grimes /* unsigned int ... */ 67df8bae1dSRodney W. Grimes #define UNION_HASH(u, l) \ 6815c73825SBruce Evans (((((uintptr_t) (u)) + ((uintptr_t) l)) >> 8) & (NHASH-1)) 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes static LIST_HEAD(unhead, union_node) unhead[NHASH]; 71df8bae1dSRodney W. Grimes static int unvplock[NHASH]; 72df8bae1dSRodney W. Grimes 73938958b9SBruce Evans static void union_dircache_r __P((struct vnode *vp, struct vnode ***vppp, 74938958b9SBruce Evans int *cntp)); 759b5e8b3aSBruce Evans static int union_list_lock __P((int ix)); 769b5e8b3aSBruce Evans static void union_list_unlock __P((int ix)); 77938958b9SBruce Evans static int union_relookup __P((struct union_mount *um, struct vnode *dvp, 78938958b9SBruce Evans struct vnode **vpp, 79938958b9SBruce Evans struct componentname *cnp, 80938958b9SBruce Evans struct componentname *cn, char *path, 81938958b9SBruce Evans int pathlen)); 8280b301c3SPoul-Henning Kamp static void union_updatevp __P((struct union_node *un, 839b5e8b3aSBruce Evans struct vnode *uppervp, 849b5e8b3aSBruce Evans struct vnode *lowervp)); 8580b301c3SPoul-Henning Kamp static void union_newlower __P((struct union_node *, struct vnode *)); 8680b301c3SPoul-Henning Kamp static void union_newupper __P((struct union_node *, struct vnode *)); 8780b301c3SPoul-Henning Kamp static int union_copyfile __P((struct vnode *, struct vnode *, 8880b301c3SPoul-Henning Kamp struct ucred *, struct proc *)); 8980b301c3SPoul-Henning Kamp static int union_vn_create __P((struct vnode **, struct union_node *, 9080b301c3SPoul-Henning Kamp struct proc *)); 9180b301c3SPoul-Henning Kamp static int union_vn_close __P((struct vnode *, int, struct ucred *, 9280b301c3SPoul-Henning Kamp struct proc *)); 939b5e8b3aSBruce Evans 94df8bae1dSRodney W. Grimes int 95df8bae1dSRodney W. Grimes union_init() 96df8bae1dSRodney W. Grimes { 97df8bae1dSRodney W. Grimes int i; 98df8bae1dSRodney W. Grimes 99df8bae1dSRodney W. Grimes for (i = 0; i < NHASH; i++) 100df8bae1dSRodney W. Grimes LIST_INIT(&unhead[i]); 101df8bae1dSRodney W. Grimes bzero((caddr_t)unvplock, sizeof(unvplock)); 10226f9a767SRodney W. Grimes return (0); 103df8bae1dSRodney W. Grimes } 104df8bae1dSRodney W. Grimes 105df8bae1dSRodney W. Grimes static int 106df8bae1dSRodney W. Grimes union_list_lock(ix) 107df8bae1dSRodney W. Grimes int ix; 108df8bae1dSRodney W. Grimes { 1092a31267eSMatthew Dillon if (unvplock[ix] & UNVP_LOCKED) { 1102a31267eSMatthew Dillon unvplock[ix] |= UNVP_WANT; 11182478919SDavid Greenman (void) tsleep((caddr_t) &unvplock[ix], PINOD, "unllck", 0); 112df8bae1dSRodney W. Grimes return (1); 113df8bae1dSRodney W. Grimes } 1142a31267eSMatthew Dillon unvplock[ix] |= UNVP_LOCKED; 115df8bae1dSRodney W. Grimes return (0); 116df8bae1dSRodney W. Grimes } 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes static void 119df8bae1dSRodney W. Grimes union_list_unlock(ix) 120df8bae1dSRodney W. Grimes int ix; 121df8bae1dSRodney W. Grimes { 1222a31267eSMatthew Dillon unvplock[ix] &= ~UNVP_LOCKED; 123df8bae1dSRodney W. Grimes 1242a31267eSMatthew Dillon if (unvplock[ix] & UNVP_WANT) { 1252a31267eSMatthew Dillon unvplock[ix] &= ~UNVP_WANT; 126df8bae1dSRodney W. Grimes wakeup((caddr_t) &unvplock[ix]); 127df8bae1dSRodney W. Grimes } 128df8bae1dSRodney W. Grimes } 129df8bae1dSRodney W. Grimes 1302a31267eSMatthew Dillon /* 1312a31267eSMatthew Dillon * union_updatevp: 1322a31267eSMatthew Dillon * 1332a31267eSMatthew Dillon * The uppervp, if not NULL, must be referenced and not locked by us 1342a31267eSMatthew Dillon * The lowervp, if not NULL, must be referenced. 1352a31267eSMatthew Dillon * 1362a31267eSMatthew Dillon * if uppervp and lowervp match pointers already installed, nothing 1372a31267eSMatthew Dillon * happens. The passed vp's (when matching) are not adjusted. This 1382a31267eSMatthew Dillon * routine may only be called by union_newupper() and union_newlower(). 1392a31267eSMatthew Dillon */ 1402a31267eSMatthew Dillon 14180b301c3SPoul-Henning Kamp static void 142df8bae1dSRodney W. Grimes union_updatevp(un, uppervp, lowervp) 143df8bae1dSRodney W. Grimes struct union_node *un; 144df8bae1dSRodney W. Grimes struct vnode *uppervp; 145df8bae1dSRodney W. Grimes struct vnode *lowervp; 146df8bae1dSRodney W. Grimes { 147df8bae1dSRodney W. Grimes int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp); 148df8bae1dSRodney W. Grimes int nhash = UNION_HASH(uppervp, lowervp); 149996c772fSJohn Dyson int docache = (lowervp != NULLVP || uppervp != NULLVP); 15080b301c3SPoul-Henning Kamp int lhash, uhash; 151df8bae1dSRodney W. Grimes 152df8bae1dSRodney W. Grimes /* 153df8bae1dSRodney W. Grimes * Ensure locking is ordered from lower to higher 154df8bae1dSRodney W. Grimes * to avoid deadlocks. 155df8bae1dSRodney W. Grimes */ 156df8bae1dSRodney W. Grimes if (nhash < ohash) { 157996c772fSJohn Dyson lhash = nhash; 158996c772fSJohn Dyson uhash = ohash; 159df8bae1dSRodney W. Grimes } else { 160996c772fSJohn Dyson lhash = ohash; 161996c772fSJohn Dyson uhash = nhash; 162df8bae1dSRodney W. Grimes } 163df8bae1dSRodney W. Grimes 1642a31267eSMatthew Dillon if (lhash != uhash) { 165996c772fSJohn Dyson while (union_list_lock(lhash)) 166996c772fSJohn Dyson continue; 1672a31267eSMatthew Dillon } 168996c772fSJohn Dyson 169996c772fSJohn Dyson while (union_list_lock(uhash)) 170996c772fSJohn Dyson continue; 171996c772fSJohn Dyson 172996c772fSJohn Dyson if (ohash != nhash || !docache) { 173996c772fSJohn Dyson if (un->un_flags & UN_CACHED) { 174996c772fSJohn Dyson un->un_flags &= ~UN_CACHED; 175996c772fSJohn Dyson LIST_REMOVE(un, un_cache); 176996c772fSJohn Dyson } 177996c772fSJohn Dyson } 178996c772fSJohn Dyson 179996c772fSJohn Dyson if (ohash != nhash) 180996c772fSJohn Dyson union_list_unlock(ohash); 181996c772fSJohn Dyson 182df8bae1dSRodney W. Grimes if (un->un_lowervp != lowervp) { 183df8bae1dSRodney W. Grimes if (un->un_lowervp) { 184df8bae1dSRodney W. Grimes vrele(un->un_lowervp); 185df8bae1dSRodney W. Grimes if (un->un_path) { 186df8bae1dSRodney W. Grimes free(un->un_path, M_TEMP); 187df8bae1dSRodney W. Grimes un->un_path = 0; 188df8bae1dSRodney W. Grimes } 189df8bae1dSRodney W. Grimes } 190df8bae1dSRodney W. Grimes un->un_lowervp = lowervp; 191996c772fSJohn Dyson un->un_lowersz = VNOVAL; 192df8bae1dSRodney W. Grimes } 193df8bae1dSRodney W. Grimes 194df8bae1dSRodney W. Grimes if (un->un_uppervp != uppervp) { 195df8bae1dSRodney W. Grimes if (un->un_uppervp) 196df8bae1dSRodney W. Grimes vrele(un->un_uppervp); 197df8bae1dSRodney W. Grimes un->un_uppervp = uppervp; 198996c772fSJohn Dyson un->un_uppersz = VNOVAL; 199df8bae1dSRodney W. Grimes } 200df8bae1dSRodney W. Grimes 201996c772fSJohn Dyson if (docache && (ohash != nhash)) { 202df8bae1dSRodney W. Grimes LIST_INSERT_HEAD(&unhead[nhash], un, un_cache); 203996c772fSJohn Dyson un->un_flags |= UN_CACHED; 204996c772fSJohn Dyson } 205df8bae1dSRodney W. Grimes 206df8bae1dSRodney W. Grimes union_list_unlock(nhash); 207df8bae1dSRodney W. Grimes } 208df8bae1dSRodney W. Grimes 2092a31267eSMatthew Dillon /* 2102a31267eSMatthew Dillon * Set a new lowervp. The passed lowervp must be referenced and will be 2112a31267eSMatthew Dillon * stored in the vp in a referenced state. 2122a31267eSMatthew Dillon */ 2132a31267eSMatthew Dillon 21480b301c3SPoul-Henning Kamp static void 215df8bae1dSRodney W. Grimes union_newlower(un, lowervp) 216df8bae1dSRodney W. Grimes struct union_node *un; 217df8bae1dSRodney W. Grimes struct vnode *lowervp; 218df8bae1dSRodney W. Grimes { 219df8bae1dSRodney W. Grimes union_updatevp(un, un->un_uppervp, lowervp); 220df8bae1dSRodney W. Grimes } 221df8bae1dSRodney W. Grimes 2222a31267eSMatthew Dillon /* 2232a31267eSMatthew Dillon * Set a new uppervp. The passed uppervp must be locked and will be 2242a31267eSMatthew Dillon * stored in the vp in a locked state. The caller should not unlock 2252a31267eSMatthew Dillon * uppervp. 2262a31267eSMatthew Dillon */ 2272a31267eSMatthew Dillon 22880b301c3SPoul-Henning Kamp static void 229df8bae1dSRodney W. Grimes union_newupper(un, uppervp) 230df8bae1dSRodney W. Grimes struct union_node *un; 231df8bae1dSRodney W. Grimes struct vnode *uppervp; 232df8bae1dSRodney W. Grimes { 233df8bae1dSRodney W. Grimes union_updatevp(un, uppervp, un->un_lowervp); 234df8bae1dSRodney W. Grimes } 235df8bae1dSRodney W. Grimes 236df8bae1dSRodney W. Grimes /* 237996c772fSJohn Dyson * Keep track of size changes in the underlying vnodes. 238996c772fSJohn Dyson * If the size changes, then callback to the vm layer 239996c772fSJohn Dyson * giving priority to the upper layer size. 240996c772fSJohn Dyson */ 241996c772fSJohn Dyson void 242996c772fSJohn Dyson union_newsize(vp, uppersz, lowersz) 243996c772fSJohn Dyson struct vnode *vp; 244996c772fSJohn Dyson off_t uppersz, lowersz; 245996c772fSJohn Dyson { 246996c772fSJohn Dyson struct union_node *un; 247996c772fSJohn Dyson off_t sz; 248996c772fSJohn Dyson 249996c772fSJohn Dyson /* only interested in regular files */ 250996c772fSJohn Dyson if (vp->v_type != VREG) 251996c772fSJohn Dyson return; 252996c772fSJohn Dyson 253996c772fSJohn Dyson un = VTOUNION(vp); 254996c772fSJohn Dyson sz = VNOVAL; 255996c772fSJohn Dyson 256996c772fSJohn Dyson if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) { 257996c772fSJohn Dyson un->un_uppersz = uppersz; 258996c772fSJohn Dyson if (sz == VNOVAL) 259996c772fSJohn Dyson sz = un->un_uppersz; 260996c772fSJohn Dyson } 261996c772fSJohn Dyson 262996c772fSJohn Dyson if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) { 263996c772fSJohn Dyson un->un_lowersz = lowersz; 264996c772fSJohn Dyson if (sz == VNOVAL) 265996c772fSJohn Dyson sz = un->un_lowersz; 266996c772fSJohn Dyson } 267996c772fSJohn Dyson 268996c772fSJohn Dyson if (sz != VNOVAL) { 2692a31267eSMatthew Dillon UDEBUG(("union: %s size now %ld\n", 2702a31267eSMatthew Dillon (uppersz != VNOVAL ? "upper" : "lower"), (long)sz)); 271996c772fSJohn Dyson vnode_pager_setsize(vp, sz); 272996c772fSJohn Dyson } 273996c772fSJohn Dyson } 274996c772fSJohn Dyson 275996c772fSJohn Dyson /* 2762a31267eSMatthew Dillon * union_allocvp: allocate a union_node and associate it with a 2772a31267eSMatthew Dillon * parent union_node and one or two vnodes. 2782a31267eSMatthew Dillon * 2792a31267eSMatthew Dillon * vpp Holds the returned vnode locked and referenced if no 2802a31267eSMatthew Dillon * error occurs. 2812a31267eSMatthew Dillon * 2822a31267eSMatthew Dillon * mp Holds the mount point. mp may or may not be busied. 2832a31267eSMatthew Dillon * allocvp makes no changes to mp. 2842a31267eSMatthew Dillon * 2852a31267eSMatthew Dillon * dvp Holds the parent union_node to the one we wish to create. 2862a31267eSMatthew Dillon * XXX may only be used to traverse an uncopied lowervp-based 2872a31267eSMatthew Dillon * tree? XXX 2882a31267eSMatthew Dillon * 2892a31267eSMatthew Dillon * dvp may or may not be locked. allocvp makes no changes 2902a31267eSMatthew Dillon * to dvp. 2912a31267eSMatthew Dillon * 2922a31267eSMatthew Dillon * upperdvp Holds the parent vnode to uppervp, generally used along 2932a31267eSMatthew Dillon * with path component information to create a shadow of 2942a31267eSMatthew Dillon * lowervp when uppervp does not exist. 2952a31267eSMatthew Dillon * 2962a31267eSMatthew Dillon * upperdvp is referenced but unlocked on entry, and will be 2972a31267eSMatthew Dillon * dereferenced on return. 2982a31267eSMatthew Dillon * 2992a31267eSMatthew Dillon * uppervp Holds the new uppervp vnode to be stored in the 3002a31267eSMatthew Dillon * union_node we are allocating. uppervp is referenced but 3012a31267eSMatthew Dillon * not locked, and will be dereferenced on return. 3022a31267eSMatthew Dillon * 3032a31267eSMatthew Dillon * lowervp Holds the new lowervp vnode to be stored in the 3042a31267eSMatthew Dillon * union_node we are allocating. uppervp is referenced but 3052a31267eSMatthew Dillon * not locked, and will be dereferenced on return. 3062a31267eSMatthew Dillon * 3072a31267eSMatthew Dillon * cnp Holds path component information to be coupled with 3082a31267eSMatthew Dillon * lowervp and upperdvp to allow unionfs to create an uppervp 3092a31267eSMatthew Dillon * later on. Only used if lowervp is valid. The conents 3102a31267eSMatthew Dillon * of cnp is only valid for the duration of the call. 3112a31267eSMatthew Dillon * 3122a31267eSMatthew Dillon * docache Determine whether this node should be entered in the 3132a31267eSMatthew Dillon * cache or whether it should be destroyed as soon as possible. 314df8bae1dSRodney W. Grimes * 315df8bae1dSRodney W. Grimes * all union_nodes are maintained on a singly-linked 316df8bae1dSRodney W. Grimes * list. new nodes are only allocated when they cannot 317df8bae1dSRodney W. Grimes * be found on this list. entries on the list are 318df8bae1dSRodney W. Grimes * removed when the vfs reclaim entry is called. 319df8bae1dSRodney W. Grimes * 320df8bae1dSRodney W. Grimes * a single lock is kept for the entire list. this is 321df8bae1dSRodney W. Grimes * needed because the getnewvnode() function can block 322df8bae1dSRodney W. Grimes * waiting for a vnode to become free, in which case there 323df8bae1dSRodney W. Grimes * may be more than one process trying to get the same 324df8bae1dSRodney W. Grimes * vnode. this lock is only taken if we are going to 325df8bae1dSRodney W. Grimes * call getnewvnode, since the kernel itself is single-threaded. 326df8bae1dSRodney W. Grimes * 327df8bae1dSRodney W. Grimes * if an entry is found on the list, then call vget() to 328df8bae1dSRodney W. Grimes * take a reference. this is done because there may be 329df8bae1dSRodney W. Grimes * zero references to it and so it needs to removed from 330df8bae1dSRodney W. Grimes * the vnode free list. 331df8bae1dSRodney W. Grimes */ 3322a31267eSMatthew Dillon 333df8bae1dSRodney W. Grimes int 3342a31267eSMatthew Dillon union_allocvp(vpp, mp, dvp, upperdvp, cnp, uppervp, lowervp, docache) 335df8bae1dSRodney W. Grimes struct vnode **vpp; 336df8bae1dSRodney W. Grimes struct mount *mp; 3372a31267eSMatthew Dillon struct vnode *dvp; /* parent union vnode */ 3382a31267eSMatthew Dillon struct vnode *upperdvp; /* parent vnode of uppervp */ 339df8bae1dSRodney W. Grimes struct componentname *cnp; /* may be null */ 340df8bae1dSRodney W. Grimes struct vnode *uppervp; /* may be null */ 341df8bae1dSRodney W. Grimes struct vnode *lowervp; /* may be null */ 342996c772fSJohn Dyson int docache; 343df8bae1dSRodney W. Grimes { 344df8bae1dSRodney W. Grimes int error; 34526f9a767SRodney W. Grimes struct union_node *un = 0; 346df8bae1dSRodney W. Grimes struct vnode *xlowervp = NULLVP; 347996c772fSJohn Dyson struct union_mount *um = MOUNTTOUNIONMOUNT(mp); 3482a31267eSMatthew Dillon struct proc *p = (cnp) ? cnp->cn_proc : curproc; 34927ed09c2SMatthew Dillon int hash = 0; 350996c772fSJohn Dyson int vflag; 351df8bae1dSRodney W. Grimes int try; 352df8bae1dSRodney W. Grimes 353df8bae1dSRodney W. Grimes if (uppervp == NULLVP && lowervp == NULLVP) 354df8bae1dSRodney W. Grimes panic("union: unidentifiable allocation"); 355df8bae1dSRodney W. Grimes 356df8bae1dSRodney W. Grimes if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { 357df8bae1dSRodney W. Grimes xlowervp = lowervp; 358df8bae1dSRodney W. Grimes lowervp = NULLVP; 359df8bae1dSRodney W. Grimes } 360df8bae1dSRodney W. Grimes 361996c772fSJohn Dyson /* detect the root vnode (and aliases) */ 362996c772fSJohn Dyson vflag = 0; 363996c772fSJohn Dyson if ((uppervp == um->um_uppervp) && 364996c772fSJohn Dyson ((lowervp == NULLVP) || lowervp == um->um_lowervp)) { 365996c772fSJohn Dyson if (lowervp == NULLVP) { 366996c772fSJohn Dyson lowervp = um->um_lowervp; 367996c772fSJohn Dyson if (lowervp != NULLVP) 368996c772fSJohn Dyson VREF(lowervp); 369996c772fSJohn Dyson } 370996c772fSJohn Dyson vflag = VROOT; 371996c772fSJohn Dyson } 372996c772fSJohn Dyson 373df8bae1dSRodney W. Grimes loop: 374996c772fSJohn Dyson if (!docache) { 375996c772fSJohn Dyson un = 0; 376996c772fSJohn Dyson } else for (try = 0; try < 3; try++) { 377df8bae1dSRodney W. Grimes switch (try) { 378df8bae1dSRodney W. Grimes case 0: 379df8bae1dSRodney W. Grimes if (lowervp == NULLVP) 380df8bae1dSRodney W. Grimes continue; 381df8bae1dSRodney W. Grimes hash = UNION_HASH(uppervp, lowervp); 382df8bae1dSRodney W. Grimes break; 383df8bae1dSRodney W. Grimes 384df8bae1dSRodney W. Grimes case 1: 385df8bae1dSRodney W. Grimes if (uppervp == NULLVP) 386df8bae1dSRodney W. Grimes continue; 387df8bae1dSRodney W. Grimes hash = UNION_HASH(uppervp, NULLVP); 388df8bae1dSRodney W. Grimes break; 389df8bae1dSRodney W. Grimes 390df8bae1dSRodney W. Grimes case 2: 391df8bae1dSRodney W. Grimes if (lowervp == NULLVP) 392df8bae1dSRodney W. Grimes continue; 393df8bae1dSRodney W. Grimes hash = UNION_HASH(NULLVP, lowervp); 394df8bae1dSRodney W. Grimes break; 395df8bae1dSRodney W. Grimes } 396df8bae1dSRodney W. Grimes 397df8bae1dSRodney W. Grimes while (union_list_lock(hash)) 398df8bae1dSRodney W. Grimes continue; 399df8bae1dSRodney W. Grimes 400df8bae1dSRodney W. Grimes for (un = unhead[hash].lh_first; un != 0; 401df8bae1dSRodney W. Grimes un = un->un_cache.le_next) { 402df8bae1dSRodney W. Grimes if ((un->un_lowervp == lowervp || 403df8bae1dSRodney W. Grimes un->un_lowervp == NULLVP) && 404df8bae1dSRodney W. Grimes (un->un_uppervp == uppervp || 405df8bae1dSRodney W. Grimes un->un_uppervp == NULLVP) && 406df8bae1dSRodney W. Grimes (UNIONTOV(un)->v_mount == mp)) { 407996c772fSJohn Dyson if (vget(UNIONTOV(un), 0, 408996c772fSJohn Dyson cnp ? cnp->cn_proc : NULL)) { 409df8bae1dSRodney W. Grimes union_list_unlock(hash); 410df8bae1dSRodney W. Grimes goto loop; 411df8bae1dSRodney W. Grimes } 412df8bae1dSRodney W. Grimes break; 413df8bae1dSRodney W. Grimes } 414df8bae1dSRodney W. Grimes } 415df8bae1dSRodney W. Grimes 416df8bae1dSRodney W. Grimes union_list_unlock(hash); 417df8bae1dSRodney W. Grimes 418df8bae1dSRodney W. Grimes if (un) 419df8bae1dSRodney W. Grimes break; 420df8bae1dSRodney W. Grimes } 421df8bae1dSRodney W. Grimes 422df8bae1dSRodney W. Grimes if (un) { 423df8bae1dSRodney W. Grimes /* 4242a31267eSMatthew Dillon * Obtain a lock on the union_node. Everything is unlocked 4252a31267eSMatthew Dillon * except for dvp, so check that case. If they match, our 4262a31267eSMatthew Dillon * new un is already locked. Otherwise we have to lock our 4272a31267eSMatthew Dillon * new un. 4282a31267eSMatthew Dillon * 4292a31267eSMatthew Dillon * A potential deadlock situation occurs when we are holding 4302a31267eSMatthew Dillon * one lock while trying to get another. We must follow 4312a31267eSMatthew Dillon * strict ordering rules to avoid it. We try to locate dvp 4322a31267eSMatthew Dillon * by scanning up from un_vnode, since the most likely 4332a31267eSMatthew Dillon * scenario is un being under dvp. 434df8bae1dSRodney W. Grimes */ 435df8bae1dSRodney W. Grimes 4362a31267eSMatthew Dillon if (dvp && un->un_vnode != dvp) { 4372a31267eSMatthew Dillon struct vnode *scan = un->un_vnode; 4382a31267eSMatthew Dillon 4392a31267eSMatthew Dillon do { 4402a31267eSMatthew Dillon scan = VTOUNION(scan)->un_pvp; 4412a31267eSMatthew Dillon } while (scan && scan->v_tag == VT_UNION && scan != dvp); 4422a31267eSMatthew Dillon if (scan != dvp) { 443df8bae1dSRodney W. Grimes /* 4442a31267eSMatthew Dillon * our new un is above dvp (we never saw dvp 4452a31267eSMatthew Dillon * while moving up the tree). 446df8bae1dSRodney W. Grimes */ 4472a31267eSMatthew Dillon VREF(dvp); 4482a31267eSMatthew Dillon VOP_UNLOCK(dvp, 0, p); 4492a31267eSMatthew Dillon error = vn_lock(un->un_vnode, LK_EXCLUSIVE, p); 4502a31267eSMatthew Dillon vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 4512a31267eSMatthew Dillon vrele(dvp); 452df8bae1dSRodney W. Grimes } else { 4532a31267eSMatthew Dillon /* 4542a31267eSMatthew Dillon * our new un is under dvp 4552a31267eSMatthew Dillon */ 4562a31267eSMatthew Dillon error = vn_lock(un->un_vnode, LK_EXCLUSIVE, p); 4572a31267eSMatthew Dillon } 4582a31267eSMatthew Dillon } else if (dvp == NULLVP) { 4592a31267eSMatthew Dillon /* 4602a31267eSMatthew Dillon * dvp is NULL, we need to lock un. 4612a31267eSMatthew Dillon */ 4622a31267eSMatthew Dillon error = vn_lock(un->un_vnode, LK_EXCLUSIVE, p); 4632a31267eSMatthew Dillon } else { 4642a31267eSMatthew Dillon /* 4652a31267eSMatthew Dillon * dvp == un->un_vnode, we are already locked. 4662a31267eSMatthew Dillon */ 4672a31267eSMatthew Dillon error = 0; 4682a31267eSMatthew Dillon } 4692a31267eSMatthew Dillon 4702a31267eSMatthew Dillon if (error) 471df8bae1dSRodney W. Grimes goto loop; 472df8bae1dSRodney W. Grimes 473df8bae1dSRodney W. Grimes /* 4742a31267eSMatthew Dillon * At this point, the union_node is locked and referenced. 4752a31267eSMatthew Dillon * 4762a31267eSMatthew Dillon * uppervp is locked and referenced or NULL, lowervp is 4772a31267eSMatthew Dillon * referenced or NULL. 478df8bae1dSRodney W. Grimes */ 4792a31267eSMatthew Dillon UDEBUG(("Modify existing un %p vn %p upper %p(refs %d) -> %p(refs %d)\n", 4802a31267eSMatthew Dillon un, un->un_vnode, un->un_uppervp, 4812a31267eSMatthew Dillon (un->un_uppervp ? un->un_uppervp->v_usecount : -99), 4822a31267eSMatthew Dillon uppervp, 4832a31267eSMatthew Dillon (uppervp ? uppervp->v_usecount : -99) 4842a31267eSMatthew Dillon )); 485df8bae1dSRodney W. Grimes 486df8bae1dSRodney W. Grimes if (uppervp != un->un_uppervp) { 4872a31267eSMatthew Dillon KASSERT(uppervp == NULL || uppervp->v_usecount > 0, ("union_allocvp: too few refs %d (at least 1 required) on uppervp", uppervp->v_usecount)); 488df8bae1dSRodney W. Grimes union_newupper(un, uppervp); 489df8bae1dSRodney W. Grimes } else if (uppervp) { 4902a31267eSMatthew Dillon KASSERT(uppervp->v_usecount > 1, ("union_allocvp: too few refs %d (at least 2 required) on uppervp", uppervp->v_usecount)); 491df8bae1dSRodney W. Grimes vrele(uppervp); 492df8bae1dSRodney W. Grimes } 493df8bae1dSRodney W. Grimes 494df8bae1dSRodney W. Grimes /* 495df8bae1dSRodney W. Grimes * Save information about the lower layer. 496df8bae1dSRodney W. Grimes * This needs to keep track of pathname 497df8bae1dSRodney W. Grimes * and directory information which union_vn_create 498df8bae1dSRodney W. Grimes * might need. 499df8bae1dSRodney W. Grimes */ 500df8bae1dSRodney W. Grimes if (lowervp != un->un_lowervp) { 501df8bae1dSRodney W. Grimes union_newlower(un, lowervp); 502996c772fSJohn Dyson if (cnp && (lowervp != NULLVP)) { 503df8bae1dSRodney W. Grimes un->un_hash = cnp->cn_hash; 504df8bae1dSRodney W. Grimes un->un_path = malloc(cnp->cn_namelen+1, 505df8bae1dSRodney W. Grimes M_TEMP, M_WAITOK); 506df8bae1dSRodney W. Grimes bcopy(cnp->cn_nameptr, un->un_path, 507df8bae1dSRodney W. Grimes cnp->cn_namelen); 508df8bae1dSRodney W. Grimes un->un_path[cnp->cn_namelen] = '\0'; 509df8bae1dSRodney W. Grimes } 510df8bae1dSRodney W. Grimes } else if (lowervp) { 511df8bae1dSRodney W. Grimes vrele(lowervp); 512df8bae1dSRodney W. Grimes } 5132a31267eSMatthew Dillon 5142a31267eSMatthew Dillon /* 5152a31267eSMatthew Dillon * and upperdvp 5162a31267eSMatthew Dillon */ 5172a31267eSMatthew Dillon if (upperdvp != un->un_dirvp) { 5182a31267eSMatthew Dillon if (un->un_dirvp) 5192a31267eSMatthew Dillon vrele(un->un_dirvp); 5202a31267eSMatthew Dillon un->un_dirvp = upperdvp; 5212a31267eSMatthew Dillon } else if (upperdvp) { 5222a31267eSMatthew Dillon vrele(upperdvp); 5232a31267eSMatthew Dillon } 5242a31267eSMatthew Dillon 525df8bae1dSRodney W. Grimes *vpp = UNIONTOV(un); 526df8bae1dSRodney W. Grimes return (0); 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes 529996c772fSJohn Dyson if (docache) { 530df8bae1dSRodney W. Grimes /* 531df8bae1dSRodney W. Grimes * otherwise lock the vp list while we call getnewvnode 532df8bae1dSRodney W. Grimes * since that can block. 533df8bae1dSRodney W. Grimes */ 534df8bae1dSRodney W. Grimes hash = UNION_HASH(uppervp, lowervp); 535df8bae1dSRodney W. Grimes 536df8bae1dSRodney W. Grimes if (union_list_lock(hash)) 537df8bae1dSRodney W. Grimes goto loop; 538996c772fSJohn Dyson } 539df8bae1dSRodney W. Grimes 5402a31267eSMatthew Dillon /* 5412a31267eSMatthew Dillon * Create new node rather then replace old node 5422a31267eSMatthew Dillon */ 5432a31267eSMatthew Dillon 544df8bae1dSRodney W. Grimes error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp); 545df8bae1dSRodney W. Grimes if (error) { 5462a31267eSMatthew Dillon /* 5472a31267eSMatthew Dillon * If an error occurs clear out vnodes. 5482a31267eSMatthew Dillon */ 549df8bae1dSRodney W. Grimes if (lowervp) 550df8bae1dSRodney W. Grimes vrele(lowervp); 5512a31267eSMatthew Dillon if (uppervp) 5522a31267eSMatthew Dillon vrele(uppervp); 5532a31267eSMatthew Dillon if (upperdvp) 5542a31267eSMatthew Dillon vrele(upperdvp); 5552a31267eSMatthew Dillon *vpp = NULL; 556df8bae1dSRodney W. Grimes goto out; 557df8bae1dSRodney W. Grimes } 558df8bae1dSRodney W. Grimes 559df8bae1dSRodney W. Grimes MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), 560df8bae1dSRodney W. Grimes M_TEMP, M_WAITOK); 561df8bae1dSRodney W. Grimes 562996c772fSJohn Dyson (*vpp)->v_flag |= vflag; 563df8bae1dSRodney W. Grimes if (uppervp) 564df8bae1dSRodney W. Grimes (*vpp)->v_type = uppervp->v_type; 565df8bae1dSRodney W. Grimes else 566df8bae1dSRodney W. Grimes (*vpp)->v_type = lowervp->v_type; 5672a31267eSMatthew Dillon 568df8bae1dSRodney W. Grimes un = VTOUNION(*vpp); 5692a31267eSMatthew Dillon bzero(un, sizeof(*un)); 5702a31267eSMatthew Dillon 5712a31267eSMatthew Dillon lockinit(&un->un_lock, PVFS, "unlock", 0, 0); 5722a31267eSMatthew Dillon vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p); 5732a31267eSMatthew Dillon 574df8bae1dSRodney W. Grimes un->un_vnode = *vpp; 575df8bae1dSRodney W. Grimes un->un_uppervp = uppervp; 576996c772fSJohn Dyson un->un_uppersz = VNOVAL; 577df8bae1dSRodney W. Grimes un->un_lowervp = lowervp; 578996c772fSJohn Dyson un->un_lowersz = VNOVAL; 5792a31267eSMatthew Dillon un->un_dirvp = upperdvp; 5802a31267eSMatthew Dillon un->un_pvp = dvp; /* only parent dir in new allocation */ 5812a31267eSMatthew Dillon if (dvp != NULLVP) 5822a31267eSMatthew Dillon VREF(dvp); 583996c772fSJohn Dyson un->un_dircache = 0; 584df8bae1dSRodney W. Grimes un->un_openl = 0; 5852a31267eSMatthew Dillon 586996c772fSJohn Dyson if (cnp && (lowervp != NULLVP)) { 587df8bae1dSRodney W. Grimes un->un_hash = cnp->cn_hash; 588df8bae1dSRodney W. Grimes un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); 589df8bae1dSRodney W. Grimes bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); 590df8bae1dSRodney W. Grimes un->un_path[cnp->cn_namelen] = '\0'; 591df8bae1dSRodney W. Grimes } else { 592df8bae1dSRodney W. Grimes un->un_hash = 0; 593df8bae1dSRodney W. Grimes un->un_path = 0; 5942a31267eSMatthew Dillon un->un_dirvp = NULL; 595df8bae1dSRodney W. Grimes } 596df8bae1dSRodney W. Grimes 597996c772fSJohn Dyson if (docache) { 598df8bae1dSRodney W. Grimes LIST_INSERT_HEAD(&unhead[hash], un, un_cache); 599996c772fSJohn Dyson un->un_flags |= UN_CACHED; 600996c772fSJohn Dyson } 601df8bae1dSRodney W. Grimes 6022a31267eSMatthew Dillon out: 603df8bae1dSRodney W. Grimes if (xlowervp) 604df8bae1dSRodney W. Grimes vrele(xlowervp); 605df8bae1dSRodney W. Grimes 606996c772fSJohn Dyson if (docache) 607df8bae1dSRodney W. Grimes union_list_unlock(hash); 608df8bae1dSRodney W. Grimes 609df8bae1dSRodney W. Grimes return (error); 610df8bae1dSRodney W. Grimes } 611df8bae1dSRodney W. Grimes 612df8bae1dSRodney W. Grimes int 613df8bae1dSRodney W. Grimes union_freevp(vp) 614df8bae1dSRodney W. Grimes struct vnode *vp; 615df8bae1dSRodney W. Grimes { 616df8bae1dSRodney W. Grimes struct union_node *un = VTOUNION(vp); 617df8bae1dSRodney W. Grimes 618996c772fSJohn Dyson if (un->un_flags & UN_CACHED) { 619996c772fSJohn Dyson un->un_flags &= ~UN_CACHED; 620df8bae1dSRodney W. Grimes LIST_REMOVE(un, un_cache); 621996c772fSJohn Dyson } 622df8bae1dSRodney W. Grimes 6232a31267eSMatthew Dillon if (un->un_pvp != NULLVP) { 624996c772fSJohn Dyson vrele(un->un_pvp); 6252a31267eSMatthew Dillon un->un_pvp = NULL; 6262a31267eSMatthew Dillon } 6272a31267eSMatthew Dillon if (un->un_uppervp != NULLVP) { 628df8bae1dSRodney W. Grimes vrele(un->un_uppervp); 6292a31267eSMatthew Dillon un->un_uppervp = NULL; 6302a31267eSMatthew Dillon } 6312a31267eSMatthew Dillon if (un->un_lowervp != NULLVP) { 632df8bae1dSRodney W. Grimes vrele(un->un_lowervp); 6332a31267eSMatthew Dillon un->un_lowervp = NULL; 6342a31267eSMatthew Dillon } 6352a31267eSMatthew Dillon if (un->un_dirvp != NULLVP) { 636df8bae1dSRodney W. Grimes vrele(un->un_dirvp); 6372a31267eSMatthew Dillon un->un_dirvp = NULL; 6382a31267eSMatthew Dillon } 6392a31267eSMatthew Dillon if (un->un_path) { 640df8bae1dSRodney W. Grimes free(un->un_path, M_TEMP); 6412a31267eSMatthew Dillon un->un_path = NULL; 6422a31267eSMatthew Dillon } 643df8bae1dSRodney W. Grimes 644df8bae1dSRodney W. Grimes FREE(vp->v_data, M_TEMP); 645df8bae1dSRodney W. Grimes vp->v_data = 0; 646df8bae1dSRodney W. Grimes 647df8bae1dSRodney W. Grimes return (0); 648df8bae1dSRodney W. Grimes } 649df8bae1dSRodney W. Grimes 650df8bae1dSRodney W. Grimes /* 651df8bae1dSRodney W. Grimes * copyfile. copy the vnode (fvp) to the vnode (tvp) 652df8bae1dSRodney W. Grimes * using a sequence of reads and writes. both (fvp) 653df8bae1dSRodney W. Grimes * and (tvp) are locked on entry and exit. 6542a31267eSMatthew Dillon * 6552a31267eSMatthew Dillon * fvp and tvp are both exclusive locked on call, but their refcount's 6562a31267eSMatthew Dillon * haven't been bumped at all. 657df8bae1dSRodney W. Grimes */ 65880b301c3SPoul-Henning Kamp static int 659996c772fSJohn Dyson union_copyfile(fvp, tvp, cred, p) 660df8bae1dSRodney W. Grimes struct vnode *fvp; 661df8bae1dSRodney W. Grimes struct vnode *tvp; 662996c772fSJohn Dyson struct ucred *cred; 663996c772fSJohn Dyson struct proc *p; 664df8bae1dSRodney W. Grimes { 665df8bae1dSRodney W. Grimes char *buf; 666df8bae1dSRodney W. Grimes struct uio uio; 667df8bae1dSRodney W. Grimes struct iovec iov; 668df8bae1dSRodney W. Grimes int error = 0; 669df8bae1dSRodney W. Grimes 670df8bae1dSRodney W. Grimes /* 671df8bae1dSRodney W. Grimes * strategy: 672df8bae1dSRodney W. Grimes * allocate a buffer of size MAXBSIZE. 673df8bae1dSRodney W. Grimes * loop doing reads and writes, keeping track 674df8bae1dSRodney W. Grimes * of the current uio offset. 675df8bae1dSRodney W. Grimes * give up at the first sign of trouble. 676df8bae1dSRodney W. Grimes */ 677df8bae1dSRodney W. Grimes 6782a31267eSMatthew Dillon bzero(&uio, sizeof(uio)); 6792a31267eSMatthew Dillon 680df8bae1dSRodney W. Grimes uio.uio_procp = p; 681df8bae1dSRodney W. Grimes uio.uio_segflg = UIO_SYSSPACE; 682df8bae1dSRodney W. Grimes uio.uio_offset = 0; 683df8bae1dSRodney W. Grimes 684996c772fSJohn Dyson VOP_LEASE(fvp, p, cred, LEASE_READ); 685996c772fSJohn Dyson VOP_LEASE(tvp, p, cred, LEASE_WRITE); 686df8bae1dSRodney W. Grimes 687df8bae1dSRodney W. Grimes buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes /* ugly loop follows... */ 690df8bae1dSRodney W. Grimes do { 691df8bae1dSRodney W. Grimes off_t offset = uio.uio_offset; 6922a31267eSMatthew Dillon int count; 6932a31267eSMatthew Dillon int bufoffset; 694df8bae1dSRodney W. Grimes 6952a31267eSMatthew Dillon /* 6962a31267eSMatthew Dillon * Setup for big read 6972a31267eSMatthew Dillon */ 698df8bae1dSRodney W. Grimes uio.uio_iov = &iov; 699df8bae1dSRodney W. Grimes uio.uio_iovcnt = 1; 700df8bae1dSRodney W. Grimes iov.iov_base = buf; 701df8bae1dSRodney W. Grimes iov.iov_len = MAXBSIZE; 702df8bae1dSRodney W. Grimes uio.uio_resid = iov.iov_len; 703df8bae1dSRodney W. Grimes uio.uio_rw = UIO_READ; 704df8bae1dSRodney W. Grimes 7052a31267eSMatthew Dillon if ((error = VOP_READ(fvp, &uio, 0, cred)) != 0) 7062a31267eSMatthew Dillon break; 7072a31267eSMatthew Dillon 7082a31267eSMatthew Dillon /* 7092a31267eSMatthew Dillon * Get bytes read, handle read eof case and setup for 7102a31267eSMatthew Dillon * write loop 7112a31267eSMatthew Dillon */ 7122a31267eSMatthew Dillon if ((count = MAXBSIZE - uio.uio_resid) == 0) 7132a31267eSMatthew Dillon break; 7142a31267eSMatthew Dillon bufoffset = 0; 7152a31267eSMatthew Dillon 7162a31267eSMatthew Dillon /* 7172a31267eSMatthew Dillon * Write until an error occurs or our buffer has been 7182a31267eSMatthew Dillon * exhausted, then update the offset for the next read. 7192a31267eSMatthew Dillon */ 7202a31267eSMatthew Dillon while (bufoffset < count) { 721df8bae1dSRodney W. Grimes uio.uio_iov = &iov; 722df8bae1dSRodney W. Grimes uio.uio_iovcnt = 1; 7232a31267eSMatthew Dillon iov.iov_base = buf + bufoffset; 7242a31267eSMatthew Dillon iov.iov_len = count - bufoffset; 7252a31267eSMatthew Dillon uio.uio_offset = offset + bufoffset; 726df8bae1dSRodney W. Grimes uio.uio_rw = UIO_WRITE; 727df8bae1dSRodney W. Grimes uio.uio_resid = iov.iov_len; 728df8bae1dSRodney W. Grimes 7292a31267eSMatthew Dillon if ((error = VOP_WRITE(tvp, &uio, 0, cred)) != 0) 730df8bae1dSRodney W. Grimes break; 7312a31267eSMatthew Dillon bufoffset += (count - bufoffset) - uio.uio_resid; 732df8bae1dSRodney W. Grimes } 7332a31267eSMatthew Dillon uio.uio_offset = offset + bufoffset; 734df8bae1dSRodney W. Grimes } while (error == 0); 735df8bae1dSRodney W. Grimes 736df8bae1dSRodney W. Grimes free(buf, M_TEMP); 737df8bae1dSRodney W. Grimes return (error); 738df8bae1dSRodney W. Grimes } 739df8bae1dSRodney W. Grimes 740df8bae1dSRodney W. Grimes /* 7412a31267eSMatthew Dillon * 7422a31267eSMatthew Dillon * un's vnode is assumed to be locked on entry and remains locked on exit. 743996c772fSJohn Dyson */ 7442a31267eSMatthew Dillon 745996c772fSJohn Dyson int 746996c772fSJohn Dyson union_copyup(un, docopy, cred, p) 747996c772fSJohn Dyson struct union_node *un; 748996c772fSJohn Dyson int docopy; 749996c772fSJohn Dyson struct ucred *cred; 750996c772fSJohn Dyson struct proc *p; 751996c772fSJohn Dyson { 752996c772fSJohn Dyson int error; 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 765996c772fSJohn Dyson error = union_vn_create(&uvp, un, p); 766996c772fSJohn Dyson if (error) 767996c772fSJohn Dyson return (error); 768996c772fSJohn Dyson 769996c772fSJohn Dyson lvp = un->un_lowervp; 770996c772fSJohn Dyson 7712a31267eSMatthew Dillon KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount)); 772996c772fSJohn Dyson if (docopy) { 773996c772fSJohn Dyson /* 774996c772fSJohn Dyson * XX - should not ignore errors 775996c772fSJohn Dyson * from VOP_CLOSE 776996c772fSJohn Dyson */ 777996c772fSJohn Dyson vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p); 778996c772fSJohn Dyson error = VOP_OPEN(lvp, FREAD, cred, p); 7792a31267eSMatthew Dillon if (error == 0 && vn_canvmio(lvp) == TRUE) 7802a31267eSMatthew Dillon error = vfs_object_create(lvp, p, cred); 781996c772fSJohn Dyson if (error == 0) { 782996c772fSJohn Dyson error = union_copyfile(lvp, uvp, cred, p); 783996c772fSJohn Dyson VOP_UNLOCK(lvp, 0, p); 784996c772fSJohn Dyson (void) VOP_CLOSE(lvp, FREAD, cred, p); 785996c772fSJohn Dyson } 786996c772fSJohn Dyson if (error == 0) 7872a31267eSMatthew Dillon UDEBUG(("union: copied up %s\n", un->un_path)); 788996c772fSJohn Dyson 789996c772fSJohn Dyson } 790996c772fSJohn Dyson VOP_UNLOCK(uvp, 0, p); 7912a31267eSMatthew Dillon union_newupper(un, uvp); 7922a31267eSMatthew Dillon KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount)); 793996c772fSJohn Dyson union_vn_close(uvp, FWRITE, cred, p); 7942a31267eSMatthew Dillon KASSERT(uvp->v_usecount > 0, ("copy: uvp refcount 0: %d", uvp->v_usecount)); 795996c772fSJohn Dyson /* 796996c772fSJohn Dyson * Subsequent IOs will go to the top layer, so 797996c772fSJohn Dyson * call close on the lower vnode and open on the 798996c772fSJohn Dyson * upper vnode to ensure that the filesystem keeps 799996c772fSJohn Dyson * its references counts right. This doesn't do 800996c772fSJohn Dyson * the right thing with (cred) and (FREAD) though. 801996c772fSJohn Dyson * Ignoring error returns is not right, either. 802996c772fSJohn Dyson */ 803996c772fSJohn Dyson if (error == 0) { 804996c772fSJohn Dyson int i; 805996c772fSJohn Dyson 806996c772fSJohn Dyson for (i = 0; i < un->un_openl; i++) { 807996c772fSJohn Dyson (void) VOP_CLOSE(lvp, FREAD, cred, p); 808996c772fSJohn Dyson (void) VOP_OPEN(uvp, FREAD, cred, p); 809996c772fSJohn Dyson } 810e3a285c7SMatthew Dillon if (un->un_openl) { 8112a31267eSMatthew Dillon if (vn_canvmio(uvp) == TRUE) 8122a31267eSMatthew Dillon error = vfs_object_create(uvp, p, cred); 813e3a285c7SMatthew Dillon } 814996c772fSJohn Dyson un->un_openl = 0; 815996c772fSJohn Dyson } 816996c772fSJohn Dyson 817996c772fSJohn Dyson return (error); 818996c772fSJohn Dyson 819996c772fSJohn Dyson } 820996c772fSJohn Dyson 8212a31267eSMatthew Dillon /* 8222a31267eSMatthew Dillon * union_relookup: 8232a31267eSMatthew Dillon * 8242a31267eSMatthew Dillon * dvp should be locked on entry and will be locked on return. No 8252a31267eSMatthew Dillon * net change in the ref count will occur. 8262a31267eSMatthew Dillon * 8272a31267eSMatthew Dillon * If an error is returned, *vpp will be invalid, otherwise it 8282a31267eSMatthew Dillon * will hold a locked, referenced vnode. If *vpp == dvp then 8292a31267eSMatthew Dillon * remember that only one exclusive lock is held. 8302a31267eSMatthew Dillon */ 8312a31267eSMatthew Dillon 832996c772fSJohn Dyson static int 833996c772fSJohn Dyson union_relookup(um, dvp, vpp, cnp, cn, path, pathlen) 834996c772fSJohn Dyson struct union_mount *um; 835996c772fSJohn Dyson struct vnode *dvp; 836996c772fSJohn Dyson struct vnode **vpp; 837996c772fSJohn Dyson struct componentname *cnp; 838996c772fSJohn Dyson struct componentname *cn; 839996c772fSJohn Dyson char *path; 840996c772fSJohn Dyson int pathlen; 841996c772fSJohn Dyson { 842996c772fSJohn Dyson int error; 843996c772fSJohn Dyson 844996c772fSJohn Dyson /* 845996c772fSJohn Dyson * A new componentname structure must be faked up because 846996c772fSJohn Dyson * there is no way to know where the upper level cnp came 847996c772fSJohn Dyson * from or what it is being used for. This must duplicate 848996c772fSJohn Dyson * some of the work done by NDINIT, some of the work done 849996c772fSJohn Dyson * by namei, some of the work done by lookup and some of 850996c772fSJohn Dyson * the work done by VOP_LOOKUP when given a CREATE flag. 851996c772fSJohn Dyson * Conclusion: Horrible. 852996c772fSJohn Dyson * 853996c772fSJohn Dyson * The pathname buffer will be FREEed by VOP_MKDIR. 854996c772fSJohn Dyson */ 855996c772fSJohn Dyson cn->cn_namelen = pathlen; 85699448ed1SJohn Dyson cn->cn_pnbuf = zalloc(namei_zone); 857996c772fSJohn Dyson bcopy(path, cn->cn_pnbuf, cn->cn_namelen); 858996c772fSJohn Dyson cn->cn_pnbuf[cn->cn_namelen] = '\0'; 859996c772fSJohn Dyson 860996c772fSJohn Dyson cn->cn_nameiop = CREATE; 8612a31267eSMatthew Dillon cn->cn_flags = (LOCKPARENT|LOCKLEAF|HASBUF|SAVENAME|ISLASTCN); 862996c772fSJohn Dyson cn->cn_proc = cnp->cn_proc; 863996c772fSJohn Dyson if (um->um_op == UNMNT_ABOVE) 864996c772fSJohn Dyson cn->cn_cred = cnp->cn_cred; 865996c772fSJohn Dyson else 866996c772fSJohn Dyson cn->cn_cred = um->um_cred; 867996c772fSJohn Dyson cn->cn_nameptr = cn->cn_pnbuf; 868996c772fSJohn Dyson cn->cn_hash = cnp->cn_hash; 869996c772fSJohn Dyson cn->cn_consume = cnp->cn_consume; 870996c772fSJohn Dyson 871996c772fSJohn Dyson VREF(dvp); 8722a31267eSMatthew Dillon VOP_UNLOCK(dvp, 0, cnp->cn_proc); 8732a31267eSMatthew Dillon 8742a31267eSMatthew Dillon /* 8752a31267eSMatthew Dillon * Pass dvp unlocked and referenced on call to relookup(). 8762a31267eSMatthew Dillon * 8772a31267eSMatthew Dillon * If an error occurs, dvp will be returned unlocked and dereferenced. 8782a31267eSMatthew Dillon */ 8792a31267eSMatthew Dillon 8802a31267eSMatthew Dillon if ((error = relookup(dvp, vpp, cn)) != 0) { 88199448ed1SJohn Dyson zfree(namei_zone, cn->cn_pnbuf); 882c598db22SEivind Eklund cn->cn_pnbuf = NULL; 8832a31267eSMatthew Dillon vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_proc); 8842a31267eSMatthew Dillon return(error); 885b422956cSPoul-Henning Kamp } 886996c772fSJohn Dyson 8872a31267eSMatthew Dillon /* 8882a31267eSMatthew Dillon * If no error occurs, dvp will be returned locked with the reference 8892a31267eSMatthew Dillon * left as before, and vpp will be returned referenced and locked. 8902a31267eSMatthew Dillon * 8912a31267eSMatthew Dillon * We want to return with dvp as it was passed to us, so we get 8922a31267eSMatthew Dillon * rid of our reference. 8932a31267eSMatthew Dillon */ 8942a31267eSMatthew Dillon vrele(dvp); 8952a31267eSMatthew Dillon return (0); 896996c772fSJohn Dyson } 897996c772fSJohn Dyson 898996c772fSJohn Dyson /* 899df8bae1dSRodney W. Grimes * Create a shadow directory in the upper layer. 900df8bae1dSRodney W. Grimes * The new vnode is returned locked. 901df8bae1dSRodney W. Grimes * 902df8bae1dSRodney W. Grimes * (um) points to the union mount structure for access to the 903df8bae1dSRodney W. Grimes * the mounting process's credentials. 9042a31267eSMatthew Dillon * (dvp) is the directory in which to create the shadow directory, 9052a31267eSMatthew Dillon * it is locked (but not ref'd) on entry and return. 906df8bae1dSRodney W. Grimes * (cnp) is the componentname to be created. 907df8bae1dSRodney W. Grimes * (vpp) is the returned newly created shadow directory, which 9082a31267eSMatthew Dillon * is returned locked and ref'd 909df8bae1dSRodney W. Grimes */ 910df8bae1dSRodney W. Grimes int 911df8bae1dSRodney W. Grimes union_mkshadow(um, dvp, cnp, vpp) 912df8bae1dSRodney W. Grimes struct union_mount *um; 913df8bae1dSRodney W. Grimes struct vnode *dvp; 914df8bae1dSRodney W. Grimes struct componentname *cnp; 915df8bae1dSRodney W. Grimes struct vnode **vpp; 916df8bae1dSRodney W. Grimes { 917df8bae1dSRodney W. Grimes int error; 918df8bae1dSRodney W. Grimes struct vattr va; 919df8bae1dSRodney W. Grimes struct proc *p = cnp->cn_proc; 920df8bae1dSRodney W. Grimes struct componentname cn; 921df8bae1dSRodney W. Grimes 922996c772fSJohn Dyson error = union_relookup(um, dvp, vpp, cnp, &cn, 923996c772fSJohn Dyson cnp->cn_nameptr, cnp->cn_namelen); 924996c772fSJohn Dyson if (error) 925996c772fSJohn Dyson return (error); 926996c772fSJohn Dyson 927996c772fSJohn Dyson if (*vpp) { 928996c772fSJohn Dyson VOP_ABORTOP(dvp, &cn); 9292a31267eSMatthew Dillon if (dvp == *vpp) 930996c772fSJohn Dyson vrele(*vpp); 9312a31267eSMatthew Dillon else 9322a31267eSMatthew Dillon vput(*vpp); 933996c772fSJohn Dyson *vpp = NULLVP; 934996c772fSJohn Dyson return (EEXIST); 935996c772fSJohn Dyson } 936996c772fSJohn Dyson 937df8bae1dSRodney W. Grimes /* 938df8bae1dSRodney W. Grimes * policy: when creating the shadow directory in the 939df8bae1dSRodney W. Grimes * upper layer, create it owned by the user who did 940df8bae1dSRodney W. Grimes * the mount, group from parent directory, and mode 941df8bae1dSRodney W. Grimes * 777 modified by umask (ie mostly identical to the 942df8bae1dSRodney W. Grimes * mkdir syscall). (jsp, kb) 943df8bae1dSRodney W. Grimes */ 944df8bae1dSRodney W. Grimes 945df8bae1dSRodney W. Grimes VATTR_NULL(&va); 946df8bae1dSRodney W. Grimes va.va_type = VDIR; 947df8bae1dSRodney W. Grimes va.va_mode = um->um_cmode; 948df8bae1dSRodney W. Grimes 949996c772fSJohn Dyson /* VOP_LEASE: dvp is locked */ 950996c772fSJohn Dyson VOP_LEASE(dvp, p, cn.cn_cred, LEASE_WRITE); 951df8bae1dSRodney W. Grimes 952df8bae1dSRodney W. Grimes error = VOP_MKDIR(dvp, vpp, &cn, &va); 9532a31267eSMatthew Dillon /*vput(dvp);*/ 954df8bae1dSRodney W. Grimes return (error); 955df8bae1dSRodney W. Grimes } 956df8bae1dSRodney W. Grimes 957df8bae1dSRodney W. Grimes /* 958996c772fSJohn Dyson * Create a whiteout entry in the upper layer. 959996c772fSJohn Dyson * 960996c772fSJohn Dyson * (um) points to the union mount structure for access to the 961996c772fSJohn Dyson * the mounting process's credentials. 962996c772fSJohn Dyson * (dvp) is the directory in which to create the whiteout. 9632a31267eSMatthew Dillon * it is locked on entry and return. 964996c772fSJohn Dyson * (cnp) is the componentname to be created. 965996c772fSJohn Dyson */ 966996c772fSJohn Dyson int 967996c772fSJohn Dyson union_mkwhiteout(um, dvp, cnp, path) 968996c772fSJohn Dyson struct union_mount *um; 969996c772fSJohn Dyson struct vnode *dvp; 970996c772fSJohn Dyson struct componentname *cnp; 971996c772fSJohn Dyson char *path; 972996c772fSJohn Dyson { 973996c772fSJohn Dyson int error; 974996c772fSJohn Dyson struct proc *p = cnp->cn_proc; 975996c772fSJohn Dyson struct vnode *wvp; 976996c772fSJohn Dyson struct componentname cn; 977996c772fSJohn Dyson 978996c772fSJohn Dyson error = union_relookup(um, dvp, &wvp, cnp, &cn, path, strlen(path)); 9792a31267eSMatthew Dillon if (error) 980996c772fSJohn Dyson return (error); 981996c772fSJohn Dyson 982996c772fSJohn Dyson if (wvp) { 983996c772fSJohn Dyson VOP_ABORTOP(dvp, &cn); 9842a31267eSMatthew Dillon if (wvp == dvp) 985996c772fSJohn Dyson vrele(wvp); 9862a31267eSMatthew Dillon else 9872a31267eSMatthew Dillon vput(wvp); 988996c772fSJohn Dyson return (EEXIST); 989996c772fSJohn Dyson } 990996c772fSJohn Dyson 991996c772fSJohn Dyson /* VOP_LEASE: dvp is locked */ 992996c772fSJohn Dyson VOP_LEASE(dvp, p, p->p_ucred, LEASE_WRITE); 993996c772fSJohn Dyson 994996c772fSJohn Dyson error = VOP_WHITEOUT(dvp, &cn, CREATE); 995996c772fSJohn Dyson if (error) 996996c772fSJohn Dyson VOP_ABORTOP(dvp, &cn); 997996c772fSJohn Dyson return (error); 998996c772fSJohn Dyson } 999996c772fSJohn Dyson 1000996c772fSJohn Dyson /* 1001df8bae1dSRodney W. Grimes * union_vn_create: creates and opens a new shadow file 1002df8bae1dSRodney W. Grimes * on the upper union layer. this function is similar 1003df8bae1dSRodney W. Grimes * in spirit to calling vn_open but it avoids calling namei(). 1004df8bae1dSRodney W. Grimes * the problem with calling namei is that a) it locks too many 1005df8bae1dSRodney W. Grimes * things, and b) it doesn't start at the "right" directory, 1006df8bae1dSRodney W. Grimes * whereas relookup is told where to start. 10072a31267eSMatthew Dillon * 10082a31267eSMatthew Dillon * On entry, the vnode associated with un is locked. It remains locked 10092a31267eSMatthew Dillon * on return. 10102a31267eSMatthew Dillon * 10112a31267eSMatthew Dillon * If no error occurs, *vpp contains a locked referenced vnode for your 10122a31267eSMatthew Dillon * use. If an error occurs *vpp iis undefined. 1013df8bae1dSRodney W. Grimes */ 101480b301c3SPoul-Henning Kamp static int 1015df8bae1dSRodney W. Grimes union_vn_create(vpp, un, p) 1016df8bae1dSRodney W. Grimes struct vnode **vpp; 1017df8bae1dSRodney W. Grimes struct union_node *un; 1018df8bae1dSRodney W. Grimes struct proc *p; 1019df8bae1dSRodney W. Grimes { 1020df8bae1dSRodney W. Grimes struct vnode *vp; 1021df8bae1dSRodney W. Grimes struct ucred *cred = p->p_ucred; 1022df8bae1dSRodney W. Grimes struct vattr vat; 1023df8bae1dSRodney W. Grimes struct vattr *vap = &vat; 1024df8bae1dSRodney W. Grimes int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL); 1025df8bae1dSRodney W. Grimes int error; 1026df8bae1dSRodney W. Grimes int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask; 1027df8bae1dSRodney W. Grimes struct componentname cn; 1028df8bae1dSRodney W. Grimes 1029df8bae1dSRodney W. Grimes *vpp = NULLVP; 1030df8bae1dSRodney W. Grimes 1031df8bae1dSRodney W. Grimes /* 1032df8bae1dSRodney W. Grimes * Build a new componentname structure (for the same 1033df8bae1dSRodney W. Grimes * reasons outlines in union_mkshadow). 1034df8bae1dSRodney W. Grimes * The difference here is that the file is owned by 1035df8bae1dSRodney W. Grimes * the current user, rather than by the person who 1036df8bae1dSRodney W. Grimes * did the mount, since the current user needs to be 1037df8bae1dSRodney W. Grimes * able to write the file (that's why it is being 1038df8bae1dSRodney W. Grimes * copied in the first place). 1039df8bae1dSRodney W. Grimes */ 1040df8bae1dSRodney W. Grimes cn.cn_namelen = strlen(un->un_path); 104199448ed1SJohn Dyson cn.cn_pnbuf = zalloc(namei_zone); 1042df8bae1dSRodney W. Grimes bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1); 1043df8bae1dSRodney W. Grimes cn.cn_nameiop = CREATE; 10442a31267eSMatthew Dillon cn.cn_flags = (LOCKPARENT|LOCKLEAF|HASBUF|SAVENAME|ISLASTCN); 1045df8bae1dSRodney W. Grimes cn.cn_proc = p; 1046df8bae1dSRodney W. Grimes cn.cn_cred = p->p_ucred; 1047df8bae1dSRodney W. Grimes cn.cn_nameptr = cn.cn_pnbuf; 1048df8bae1dSRodney W. Grimes cn.cn_hash = un->un_hash; 1049df8bae1dSRodney W. Grimes cn.cn_consume = 0; 1050df8bae1dSRodney W. Grimes 10512a31267eSMatthew Dillon /* 10522a31267eSMatthew Dillon * Pass dvp unlocked and referenced on call to relookup(). 10532a31267eSMatthew Dillon * 10542a31267eSMatthew Dillon * If an error occurs, dvp will be returned unlocked and dereferenced. 10552a31267eSMatthew Dillon */ 1056df8bae1dSRodney W. Grimes VREF(un->un_dirvp); 10573a773ad0SPoul-Henning Kamp error = relookup(un->un_dirvp, &vp, &cn); 10583a773ad0SPoul-Henning Kamp if (error) 1059df8bae1dSRodney W. Grimes return (error); 1060df8bae1dSRodney W. Grimes 10612a31267eSMatthew Dillon /* 10622a31267eSMatthew Dillon * If no error occurs, dvp will be returned locked with the reference 10632a31267eSMatthew Dillon * left as before, and vpp will be returned referenced and locked. 10642a31267eSMatthew Dillon */ 1065df8bae1dSRodney W. Grimes if (vp) { 1066df8bae1dSRodney W. Grimes vput(un->un_dirvp); 10672a31267eSMatthew Dillon VOP_ABORTOP(un->un_dirvp, &cn); 10682a31267eSMatthew Dillon if (vp == un->un_dirvp) 1069df8bae1dSRodney W. Grimes vrele(vp); 10702a31267eSMatthew Dillon else 10712a31267eSMatthew Dillon vput(vp); 1072df8bae1dSRodney W. Grimes return (EEXIST); 1073df8bae1dSRodney W. Grimes } 1074df8bae1dSRodney W. Grimes 1075df8bae1dSRodney W. Grimes /* 1076df8bae1dSRodney W. Grimes * Good - there was no race to create the file 1077df8bae1dSRodney W. Grimes * so go ahead and create it. The permissions 1078df8bae1dSRodney W. Grimes * on the file will be 0666 modified by the 1079df8bae1dSRodney W. Grimes * current user's umask. Access to the file, while 1080df8bae1dSRodney W. Grimes * it is unioned, will require access to the top *and* 1081df8bae1dSRodney W. Grimes * bottom files. Access when not unioned will simply 1082df8bae1dSRodney W. Grimes * require access to the top-level file. 1083df8bae1dSRodney W. Grimes * TODO: confirm choice of access permissions. 1084df8bae1dSRodney W. Grimes */ 1085df8bae1dSRodney W. Grimes VATTR_NULL(vap); 1086df8bae1dSRodney W. Grimes vap->va_type = VREG; 1087df8bae1dSRodney W. Grimes vap->va_mode = cmode; 1088996c772fSJohn Dyson VOP_LEASE(un->un_dirvp, p, cred, LEASE_WRITE); 10897be2d300SMike Smith error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap); 10907be2d300SMike Smith vput(un->un_dirvp); 10917be2d300SMike Smith if (error) 1092df8bae1dSRodney W. Grimes return (error); 1093df8bae1dSRodney W. Grimes 10943a773ad0SPoul-Henning Kamp error = VOP_OPEN(vp, fmode, cred, p); 10952a31267eSMatthew Dillon if (error == 0 && vn_canvmio(vp) == TRUE) 10962a31267eSMatthew Dillon error = vfs_object_create(vp, p, cred); 10973a773ad0SPoul-Henning Kamp if (error) { 1098df8bae1dSRodney W. Grimes vput(vp); 1099df8bae1dSRodney W. Grimes return (error); 1100df8bae1dSRodney W. Grimes } 1101df8bae1dSRodney W. Grimes vp->v_writecount++; 1102df8bae1dSRodney W. Grimes *vpp = vp; 1103df8bae1dSRodney W. Grimes return (0); 1104df8bae1dSRodney W. Grimes } 1105df8bae1dSRodney W. Grimes 110680b301c3SPoul-Henning Kamp static int 1107df8bae1dSRodney W. Grimes union_vn_close(vp, fmode, cred, p) 1108df8bae1dSRodney W. Grimes struct vnode *vp; 1109df8bae1dSRodney W. Grimes int fmode; 1110df8bae1dSRodney W. Grimes struct ucred *cred; 1111df8bae1dSRodney W. Grimes struct proc *p; 1112df8bae1dSRodney W. Grimes { 1113996c772fSJohn Dyson 1114df8bae1dSRodney W. Grimes if (fmode & FWRITE) 1115df8bae1dSRodney W. Grimes --vp->v_writecount; 1116cf2455a3SBruce Evans return (VOP_CLOSE(vp, fmode, cred, p)); 1117df8bae1dSRodney W. Grimes } 1118df8bae1dSRodney W. Grimes 11192a31267eSMatthew Dillon #if 0 11202a31267eSMatthew Dillon 11212a31267eSMatthew Dillon /* 11222a31267eSMatthew Dillon * union_removed_upper: 11232a31267eSMatthew Dillon * 11242a31267eSMatthew Dillon * called with union_node unlocked. XXX 11252a31267eSMatthew Dillon */ 11262a31267eSMatthew Dillon 1127df8bae1dSRodney W. Grimes void 1128df8bae1dSRodney W. Grimes union_removed_upper(un) 1129df8bae1dSRodney W. Grimes struct union_node *un; 1130df8bae1dSRodney W. Grimes { 1131996c772fSJohn Dyson struct proc *p = curproc; /* XXX */ 1132b69aa7f1SKATO Takenori struct vnode **vpp; 1133df8bae1dSRodney W. Grimes 1134b69aa7f1SKATO Takenori /* 1135b69aa7f1SKATO Takenori * Do not set the uppervp to NULLVP. If lowervp is NULLVP, 11369758931dSKATO Takenori * union node will have neither uppervp nor lowervp. We remove 1137b69aa7f1SKATO Takenori * the union node from cache, so that it will not be referrenced. 1138b69aa7f1SKATO Takenori */ 1139df8bae1dSRodney W. Grimes union_newupper(un, NULLVP); 1140b69aa7f1SKATO Takenori if (un->un_dircache != 0) { 1141b69aa7f1SKATO Takenori for (vpp = un->un_dircache; *vpp != NULLVP; vpp++) 1142b69aa7f1SKATO Takenori vrele(*vpp); 1143b69aa7f1SKATO Takenori free(un->un_dircache, M_TEMP); 1144b69aa7f1SKATO Takenori un->un_dircache = 0; 1145b69aa7f1SKATO Takenori } 1146b69aa7f1SKATO Takenori 1147996c772fSJohn Dyson if (un->un_flags & UN_CACHED) { 1148996c772fSJohn Dyson un->un_flags &= ~UN_CACHED; 1149996c772fSJohn Dyson LIST_REMOVE(un, un_cache); 1150df8bae1dSRodney W. Grimes } 1151996c772fSJohn Dyson } 1152996c772fSJohn Dyson 1153996c772fSJohn Dyson #endif 1154996c772fSJohn Dyson 1155996c772fSJohn Dyson /* 1156996c772fSJohn Dyson * determine whether a whiteout is needed 1157996c772fSJohn Dyson * during a remove/rmdir operation. 1158996c772fSJohn Dyson */ 1159996c772fSJohn Dyson int 1160996c772fSJohn Dyson union_dowhiteout(un, cred, p) 1161996c772fSJohn Dyson struct union_node *un; 1162996c772fSJohn Dyson struct ucred *cred; 1163996c772fSJohn Dyson struct proc *p; 1164996c772fSJohn Dyson { 1165996c772fSJohn Dyson struct vattr va; 1166996c772fSJohn Dyson 1167996c772fSJohn Dyson if (un->un_lowervp != NULLVP) 1168996c772fSJohn Dyson return (1); 1169996c772fSJohn Dyson 1170996c772fSJohn Dyson if (VOP_GETATTR(un->un_uppervp, &va, cred, p) == 0 && 1171996c772fSJohn Dyson (va.va_flags & OPAQUE)) 1172996c772fSJohn Dyson return (1); 1173996c772fSJohn Dyson 1174996c772fSJohn Dyson return (0); 1175996c772fSJohn Dyson } 1176996c772fSJohn Dyson 1177996c772fSJohn Dyson static void 1178996c772fSJohn Dyson union_dircache_r(vp, vppp, cntp) 1179996c772fSJohn Dyson struct vnode *vp; 1180996c772fSJohn Dyson struct vnode ***vppp; 1181996c772fSJohn Dyson int *cntp; 1182996c772fSJohn Dyson { 1183996c772fSJohn Dyson struct union_node *un; 1184996c772fSJohn Dyson 1185996c772fSJohn Dyson if (vp->v_op != union_vnodeop_p) { 1186996c772fSJohn Dyson if (vppp) { 1187996c772fSJohn Dyson VREF(vp); 1188996c772fSJohn Dyson *(*vppp)++ = vp; 1189996c772fSJohn Dyson if (--(*cntp) == 0) 1190996c772fSJohn Dyson panic("union: dircache table too small"); 1191996c772fSJohn Dyson } else { 1192996c772fSJohn Dyson (*cntp)++; 1193996c772fSJohn Dyson } 1194996c772fSJohn Dyson 1195996c772fSJohn Dyson return; 1196996c772fSJohn Dyson } 1197996c772fSJohn Dyson 1198996c772fSJohn Dyson un = VTOUNION(vp); 1199996c772fSJohn Dyson if (un->un_uppervp != NULLVP) 1200996c772fSJohn Dyson union_dircache_r(un->un_uppervp, vppp, cntp); 1201996c772fSJohn Dyson if (un->un_lowervp != NULLVP) 1202996c772fSJohn Dyson union_dircache_r(un->un_lowervp, vppp, cntp); 1203996c772fSJohn Dyson } 1204996c772fSJohn Dyson 1205996c772fSJohn Dyson struct vnode * 1206996c772fSJohn Dyson union_dircache(vp, p) 1207996c772fSJohn Dyson struct vnode *vp; 1208996c772fSJohn Dyson struct proc *p; 1209996c772fSJohn Dyson { 1210996c772fSJohn Dyson int cnt; 1211996c772fSJohn Dyson struct vnode *nvp; 1212996c772fSJohn Dyson struct vnode **vpp; 1213996c772fSJohn Dyson struct vnode **dircache; 1214996c772fSJohn Dyson struct union_node *un; 1215996c772fSJohn Dyson int error; 1216996c772fSJohn Dyson 1217996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1218996c772fSJohn Dyson dircache = VTOUNION(vp)->un_dircache; 1219996c772fSJohn Dyson 1220996c772fSJohn Dyson nvp = NULLVP; 1221996c772fSJohn Dyson 12222a31267eSMatthew Dillon if (dircache == NULL) { 1223996c772fSJohn Dyson cnt = 0; 1224996c772fSJohn Dyson union_dircache_r(vp, 0, &cnt); 1225996c772fSJohn Dyson cnt++; 12262a31267eSMatthew Dillon dircache = malloc(cnt * sizeof(struct vnode *), 1227996c772fSJohn Dyson M_TEMP, M_WAITOK); 1228996c772fSJohn Dyson vpp = dircache; 1229996c772fSJohn Dyson union_dircache_r(vp, &vpp, &cnt); 1230996c772fSJohn Dyson *vpp = NULLVP; 1231996c772fSJohn Dyson vpp = dircache + 1; 1232996c772fSJohn Dyson } else { 1233996c772fSJohn Dyson vpp = dircache; 1234996c772fSJohn Dyson do { 1235996c772fSJohn Dyson if (*vpp++ == VTOUNION(vp)->un_uppervp) 1236996c772fSJohn Dyson break; 1237996c772fSJohn Dyson } while (*vpp != NULLVP); 1238996c772fSJohn Dyson } 1239996c772fSJohn Dyson 1240996c772fSJohn Dyson if (*vpp == NULLVP) 1241996c772fSJohn Dyson goto out; 1242996c772fSJohn Dyson 12432a31267eSMatthew Dillon /*vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, p);*/ 12442a31267eSMatthew Dillon UDEBUG(("ALLOCVP-3 %p ref %d\n", *vpp, (*vpp ? (*vpp)->v_usecount : -99))); 1245996c772fSJohn Dyson VREF(*vpp); 12462a31267eSMatthew Dillon error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, NULL, *vpp, NULLVP, 0); 12472a31267eSMatthew Dillon UDEBUG(("ALLOCVP-3B %p ref %d\n", nvp, (*vpp ? (*vpp)->v_usecount : -99))); 1248996c772fSJohn Dyson if (error) 1249996c772fSJohn Dyson goto out; 1250996c772fSJohn Dyson 1251996c772fSJohn Dyson VTOUNION(vp)->un_dircache = 0; 1252996c772fSJohn Dyson un = VTOUNION(nvp); 1253996c772fSJohn Dyson un->un_dircache = dircache; 1254996c772fSJohn Dyson 1255996c772fSJohn Dyson out: 1256996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 1257996c772fSJohn Dyson return (nvp); 1258df8bae1dSRodney W. Grimes } 12598c14bf40SPeter Wemm 12608c14bf40SPeter Wemm /* 12612a31267eSMatthew Dillon * Guarentee coherency with the VM cache by invalidating any clean VM pages 12622a31267eSMatthew Dillon * associated with this write and updating any dirty VM pages. Since our 12632a31267eSMatthew Dillon * vnode is locked, other processes will not be able to read the pages in 12642a31267eSMatthew Dillon * again until after our write completes. 12652a31267eSMatthew Dillon * 12662a31267eSMatthew Dillon * We also have to be coherent with reads, by flushing any pending dirty 12672a31267eSMatthew Dillon * pages prior to issuing the read. 12682a31267eSMatthew Dillon * 12692a31267eSMatthew Dillon * XXX this is somewhat of a hack at the moment. To support this properly 12702a31267eSMatthew Dillon * we would have to be able to run VOP_READ and VOP_WRITE through the VM 12712a31267eSMatthew Dillon * cache. Then we wouldn't need to worry about coherency. 12722a31267eSMatthew Dillon */ 12732a31267eSMatthew Dillon 12742a31267eSMatthew Dillon void 12752a31267eSMatthew Dillon union_vm_coherency(struct vnode *vp, struct uio *uio, int cleanfls) 12762a31267eSMatthew Dillon { 12772a31267eSMatthew Dillon vm_object_t object; 12782a31267eSMatthew Dillon vm_pindex_t pstart; 12792a31267eSMatthew Dillon vm_pindex_t pend; 12802a31267eSMatthew Dillon int pgoff; 12812a31267eSMatthew Dillon 12822a31267eSMatthew Dillon if ((object = vp->v_object) == NULL) 12832a31267eSMatthew Dillon return; 12842a31267eSMatthew Dillon 12852a31267eSMatthew Dillon pgoff = uio->uio_offset & PAGE_MASK; 12862a31267eSMatthew Dillon pstart = uio->uio_offset / PAGE_SIZE; 12872a31267eSMatthew Dillon pend = pstart + (uio->uio_resid + pgoff + PAGE_MASK) / PAGE_SIZE; 12882a31267eSMatthew Dillon 12892a31267eSMatthew Dillon vm_object_page_clean(object, pstart, pend, OBJPC_SYNC); 12902a31267eSMatthew Dillon if (cleanfls) 12912a31267eSMatthew Dillon vm_object_page_remove(object, pstart, pend, TRUE); 12922a31267eSMatthew Dillon } 12932a31267eSMatthew Dillon 12942a31267eSMatthew Dillon /* 12958c14bf40SPeter Wemm * Module glue to remove #ifdef UNION from vfs_syscalls.c 12968c14bf40SPeter Wemm */ 12978c14bf40SPeter Wemm static int 12988c14bf40SPeter Wemm union_dircheck(struct proc *p, struct vnode **vp, struct file *fp) 12998c14bf40SPeter Wemm { 13008c14bf40SPeter Wemm int error = 0; 13018c14bf40SPeter Wemm 13028c14bf40SPeter Wemm if ((*vp)->v_op == union_vnodeop_p) { 13038c14bf40SPeter Wemm struct vnode *lvp; 13048c14bf40SPeter Wemm 13058c14bf40SPeter Wemm lvp = union_dircache(*vp, p); 13068c14bf40SPeter Wemm if (lvp != NULLVP) { 13078c14bf40SPeter Wemm struct vattr va; 13088c14bf40SPeter Wemm 13098c14bf40SPeter Wemm /* 13108c14bf40SPeter Wemm * If the directory is opaque, 13118c14bf40SPeter Wemm * then don't show lower entries 13128c14bf40SPeter Wemm */ 13138c14bf40SPeter Wemm error = VOP_GETATTR(*vp, &va, fp->f_cred, p); 13148c14bf40SPeter Wemm if (va.va_flags & OPAQUE) { 13158c14bf40SPeter Wemm vput(lvp); 13168c14bf40SPeter Wemm lvp = NULL; 13178c14bf40SPeter Wemm } 13188c14bf40SPeter Wemm } 13198c14bf40SPeter Wemm 13208c14bf40SPeter Wemm if (lvp != NULLVP) { 13218c14bf40SPeter Wemm error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 13222a31267eSMatthew Dillon if (error == 0 && vn_canvmio(lvp) == TRUE) 13232a31267eSMatthew Dillon error = vfs_object_create(lvp, p, fp->f_cred); 13248c14bf40SPeter Wemm if (error) { 13258c14bf40SPeter Wemm vput(lvp); 13268c14bf40SPeter Wemm return (error); 13278c14bf40SPeter Wemm } 13288c14bf40SPeter Wemm VOP_UNLOCK(lvp, 0, p); 13298c14bf40SPeter Wemm fp->f_data = (caddr_t) lvp; 13308c14bf40SPeter Wemm fp->f_offset = 0; 13318c14bf40SPeter Wemm error = vn_close(*vp, FREAD, fp->f_cred, p); 13328c14bf40SPeter Wemm if (error) 13338c14bf40SPeter Wemm return (error); 13348c14bf40SPeter Wemm *vp = lvp; 13358c14bf40SPeter Wemm return -1; /* goto unionread */ 13368c14bf40SPeter Wemm } 13378c14bf40SPeter Wemm } 13388c14bf40SPeter Wemm return error; 13398c14bf40SPeter Wemm } 13408c14bf40SPeter Wemm 1341c25ded31SBruce Evans static int 1342c25ded31SBruce Evans union_modevent(module_t mod, int type, void *data) 13438c14bf40SPeter Wemm { 13448c14bf40SPeter Wemm switch (type) { 13458c14bf40SPeter Wemm case MOD_LOAD: 13468c14bf40SPeter Wemm union_dircheckp = union_dircheck; 13478c14bf40SPeter Wemm break; 13488c14bf40SPeter Wemm case MOD_UNLOAD: 13498c14bf40SPeter Wemm union_dircheckp = NULL; 13508c14bf40SPeter Wemm break; 13518c14bf40SPeter Wemm default: 13528c14bf40SPeter Wemm break; 13538c14bf40SPeter Wemm } 13548c14bf40SPeter Wemm return 0; 13558c14bf40SPeter Wemm } 13562a31267eSMatthew Dillon 13578c14bf40SPeter Wemm static moduledata_t union_mod = { 13588c14bf40SPeter Wemm "union_dircheck", 13598c14bf40SPeter Wemm union_modevent, 13608c14bf40SPeter Wemm NULL 13618c14bf40SPeter Wemm }; 13622a31267eSMatthew Dillon 13638c14bf40SPeter Wemm DECLARE_MODULE(union_dircheck, union_mod, SI_SUB_VFS, SI_ORDER_ANY); 1364