1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1992, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from software donated to Berkeley by 6df8bae1dSRodney W. Grimes * Jan-Simon Pendry. 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 9df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 10df8bae1dSRodney W. Grimes * are met: 11df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 12df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 13df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 15df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 16df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 17df8bae1dSRodney W. Grimes * must display the following acknowledgement: 18df8bae1dSRodney W. Grimes * This product includes software developed by the University of 19df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 20df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 36df8bae1dSRodney W. Grimes * @(#)null_subr.c 8.4 (Berkeley) 1/21/94 37df8bae1dSRodney W. Grimes * 389b5e8b3aSBruce Evans * $Id: null_subr.c,v 1.4 1995/12/03 14:38:49 bde Exp $ 39df8bae1dSRodney W. Grimes */ 40df8bae1dSRodney W. Grimes 41df8bae1dSRodney W. Grimes #include <sys/param.h> 42df8bae1dSRodney W. Grimes #include <sys/systm.h> 43df8bae1dSRodney W. Grimes #include <sys/time.h> 44df8bae1dSRodney W. Grimes #include <sys/types.h> 45df8bae1dSRodney W. Grimes #include <sys/vnode.h> 46df8bae1dSRodney W. Grimes #include <sys/mount.h> 47df8bae1dSRodney W. Grimes #include <sys/namei.h> 48df8bae1dSRodney W. Grimes #include <sys/malloc.h> 49df8bae1dSRodney W. Grimes #include <miscfs/nullfs/null.h> 50df8bae1dSRodney W. Grimes 519b5e8b3aSBruce Evans extern int nullfs_init __P((void)); 529b5e8b3aSBruce Evans 53df8bae1dSRodney W. Grimes #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 54df8bae1dSRodney W. Grimes #define NNULLNODECACHE 16 55df8bae1dSRodney W. Grimes #define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes /* 58df8bae1dSRodney W. Grimes * Null layer cache: 59df8bae1dSRodney W. Grimes * Each cache entry holds a reference to the lower vnode 60df8bae1dSRodney W. Grimes * along with a pointer to the alias vnode. When an 61df8bae1dSRodney W. Grimes * entry is added the lower vnode is VREF'd. When the 62df8bae1dSRodney W. Grimes * alias is removed the lower vnode is vrele'd. 63df8bae1dSRodney W. Grimes */ 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes /* 66df8bae1dSRodney W. Grimes * Cache head 67df8bae1dSRodney W. Grimes */ 68df8bae1dSRodney W. Grimes struct null_node_cache { 69df8bae1dSRodney W. Grimes struct null_node *ac_forw; 70df8bae1dSRodney W. Grimes struct null_node *ac_back; 71df8bae1dSRodney W. Grimes }; 72df8bae1dSRodney W. Grimes 73df8bae1dSRodney W. Grimes static struct null_node_cache null_node_cache[NNULLNODECACHE]; 74df8bae1dSRodney W. Grimes 759b5e8b3aSBruce Evans static int null_node_alloc __P((struct mount *mp, struct vnode *lowervp, 769b5e8b3aSBruce Evans struct vnode **vpp)); 779b5e8b3aSBruce Evans static struct vnode * 789b5e8b3aSBruce Evans null_node_find __P((struct mount *mp, struct vnode *lowervp)); 799b5e8b3aSBruce Evans static struct null_node_cache * 809b5e8b3aSBruce Evans null_node_hash __P((struct vnode *lowervp)); 819b5e8b3aSBruce Evans 82df8bae1dSRodney W. Grimes /* 83df8bae1dSRodney W. Grimes * Initialise cache headers 84df8bae1dSRodney W. Grimes */ 8526f9a767SRodney W. Grimes int 86df8bae1dSRodney W. Grimes nullfs_init() 87df8bae1dSRodney W. Grimes { 88df8bae1dSRodney W. Grimes struct null_node_cache *ac; 89df8bae1dSRodney W. Grimes #ifdef NULLFS_DIAGNOSTIC 90df8bae1dSRodney W. Grimes printf("nullfs_init\n"); /* printed during system boot */ 91df8bae1dSRodney W. Grimes #endif 92df8bae1dSRodney W. Grimes 93df8bae1dSRodney W. Grimes for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) 94df8bae1dSRodney W. Grimes ac->ac_forw = ac->ac_back = (struct null_node *) ac; 9526f9a767SRodney W. Grimes return (0); 96df8bae1dSRodney W. Grimes } 97df8bae1dSRodney W. Grimes 98df8bae1dSRodney W. Grimes /* 99df8bae1dSRodney W. Grimes * Compute hash list for given lower vnode 100df8bae1dSRodney W. Grimes */ 101df8bae1dSRodney W. Grimes static struct null_node_cache * 102df8bae1dSRodney W. Grimes null_node_hash(lowervp) 103df8bae1dSRodney W. Grimes struct vnode *lowervp; 104df8bae1dSRodney W. Grimes { 105df8bae1dSRodney W. Grimes 106df8bae1dSRodney W. Grimes return (&null_node_cache[NULL_NHASH(lowervp)]); 107df8bae1dSRodney W. Grimes } 108df8bae1dSRodney W. Grimes 109df8bae1dSRodney W. Grimes /* 110df8bae1dSRodney W. Grimes * Return a VREF'ed alias for lower vnode if already exists, else 0. 111df8bae1dSRodney W. Grimes */ 112df8bae1dSRodney W. Grimes static struct vnode * 113df8bae1dSRodney W. Grimes null_node_find(mp, lowervp) 114df8bae1dSRodney W. Grimes struct mount *mp; 115df8bae1dSRodney W. Grimes struct vnode *lowervp; 116df8bae1dSRodney W. Grimes { 117df8bae1dSRodney W. Grimes struct null_node_cache *hd; 118df8bae1dSRodney W. Grimes struct null_node *a; 119df8bae1dSRodney W. Grimes struct vnode *vp; 120df8bae1dSRodney W. Grimes 121df8bae1dSRodney W. Grimes /* 122df8bae1dSRodney W. Grimes * Find hash base, and then search the (two-way) linked 123df8bae1dSRodney W. Grimes * list looking for a null_node structure which is referencing 124df8bae1dSRodney W. Grimes * the lower vnode. If found, the increment the null_node 125df8bae1dSRodney W. Grimes * reference count (but NOT the lower vnode's VREF counter). 126df8bae1dSRodney W. Grimes */ 127df8bae1dSRodney W. Grimes hd = null_node_hash(lowervp); 128df8bae1dSRodney W. Grimes loop: 129df8bae1dSRodney W. Grimes for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 130df8bae1dSRodney W. Grimes if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 131df8bae1dSRodney W. Grimes vp = NULLTOV(a); 132df8bae1dSRodney W. Grimes /* 133df8bae1dSRodney W. Grimes * We need vget for the VXLOCK 134df8bae1dSRodney W. Grimes * stuff, but we don't want to lock 135df8bae1dSRodney W. Grimes * the lower node. 136df8bae1dSRodney W. Grimes */ 137df8bae1dSRodney W. Grimes if (vget(vp, 0)) { 138df8bae1dSRodney W. Grimes printf ("null_node_find: vget failed.\n"); 139df8bae1dSRodney W. Grimes goto loop; 140df8bae1dSRodney W. Grimes }; 141df8bae1dSRodney W. Grimes return (vp); 142df8bae1dSRodney W. Grimes } 143df8bae1dSRodney W. Grimes } 144df8bae1dSRodney W. Grimes 145df8bae1dSRodney W. Grimes return NULL; 146df8bae1dSRodney W. Grimes } 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes 149df8bae1dSRodney W. Grimes /* 150df8bae1dSRodney W. Grimes * Make a new null_node node. 151df8bae1dSRodney W. Grimes * Vp is the alias vnode, lofsvp is the lower vnode. 152df8bae1dSRodney W. Grimes * Maintain a reference to (lowervp). 153df8bae1dSRodney W. Grimes */ 154df8bae1dSRodney W. Grimes static int 155df8bae1dSRodney W. Grimes null_node_alloc(mp, lowervp, vpp) 156df8bae1dSRodney W. Grimes struct mount *mp; 157df8bae1dSRodney W. Grimes struct vnode *lowervp; 158df8bae1dSRodney W. Grimes struct vnode **vpp; 159df8bae1dSRodney W. Grimes { 160df8bae1dSRodney W. Grimes struct null_node_cache *hd; 161df8bae1dSRodney W. Grimes struct null_node *xp; 162df8bae1dSRodney W. Grimes struct vnode *othervp, *vp; 163df8bae1dSRodney W. Grimes int error; 164df8bae1dSRodney W. Grimes 165623ae52eSPoul-Henning Kamp error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp); 166623ae52eSPoul-Henning Kamp if (error) 167df8bae1dSRodney W. Grimes return (error); 168df8bae1dSRodney W. Grimes vp = *vpp; 169df8bae1dSRodney W. Grimes 170df8bae1dSRodney W. Grimes MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 171df8bae1dSRodney W. Grimes vp->v_type = lowervp->v_type; 172df8bae1dSRodney W. Grimes xp->null_vnode = vp; 173df8bae1dSRodney W. Grimes vp->v_data = xp; 174df8bae1dSRodney W. Grimes xp->null_lowervp = lowervp; 175df8bae1dSRodney W. Grimes /* 176df8bae1dSRodney W. Grimes * Before we insert our new node onto the hash chains, 177df8bae1dSRodney W. Grimes * check to see if someone else has beaten us to it. 178df8bae1dSRodney W. Grimes * (We could have slept in MALLOC.) 179df8bae1dSRodney W. Grimes */ 1802e52c1f9SBruce Evans othervp = null_node_find(mp, lowervp); 181623ae52eSPoul-Henning Kamp if (othervp) { 182df8bae1dSRodney W. Grimes FREE(xp, M_TEMP); 183df8bae1dSRodney W. Grimes vp->v_type = VBAD; /* node is discarded */ 184df8bae1dSRodney W. Grimes vp->v_usecount = 0; /* XXX */ 185df8bae1dSRodney W. Grimes *vpp = othervp; 186df8bae1dSRodney W. Grimes return 0; 187df8bae1dSRodney W. Grimes }; 188df8bae1dSRodney W. Grimes VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 189df8bae1dSRodney W. Grimes hd = null_node_hash(lowervp); 190df8bae1dSRodney W. Grimes insque(xp, hd); 191df8bae1dSRodney W. Grimes return 0; 192df8bae1dSRodney W. Grimes } 193df8bae1dSRodney W. Grimes 194df8bae1dSRodney W. Grimes 195df8bae1dSRodney W. Grimes /* 196df8bae1dSRodney W. Grimes * Try to find an existing null_node vnode refering 197df8bae1dSRodney W. Grimes * to it, otherwise make a new null_node vnode which 198df8bae1dSRodney W. Grimes * contains a reference to the lower vnode. 199df8bae1dSRodney W. Grimes */ 200df8bae1dSRodney W. Grimes int 201df8bae1dSRodney W. Grimes null_node_create(mp, lowervp, newvpp) 202df8bae1dSRodney W. Grimes struct mount *mp; 203df8bae1dSRodney W. Grimes struct vnode *lowervp; 204df8bae1dSRodney W. Grimes struct vnode **newvpp; 205df8bae1dSRodney W. Grimes { 206df8bae1dSRodney W. Grimes struct vnode *aliasvp; 207df8bae1dSRodney W. Grimes 208623ae52eSPoul-Henning Kamp aliasvp = null_node_find(mp, lowervp); 209623ae52eSPoul-Henning Kamp if (aliasvp) { 210df8bae1dSRodney W. Grimes /* 211df8bae1dSRodney W. Grimes * null_node_find has taken another reference 212df8bae1dSRodney W. Grimes * to the alias vnode. 213df8bae1dSRodney W. Grimes */ 214df8bae1dSRodney W. Grimes #ifdef NULLFS_DIAGNOSTIC 215df8bae1dSRodney W. Grimes vprint("null_node_create: exists", NULLTOV(ap)); 216df8bae1dSRodney W. Grimes #endif 217df8bae1dSRodney W. Grimes /* VREF(aliasvp); --- done in null_node_find */ 218df8bae1dSRodney W. Grimes } else { 219df8bae1dSRodney W. Grimes int error; 220df8bae1dSRodney W. Grimes 221df8bae1dSRodney W. Grimes /* 222df8bae1dSRodney W. Grimes * Get new vnode. 223df8bae1dSRodney W. Grimes */ 224df8bae1dSRodney W. Grimes #ifdef NULLFS_DIAGNOSTIC 225df8bae1dSRodney W. Grimes printf("null_node_create: create new alias vnode\n"); 226df8bae1dSRodney W. Grimes #endif 227df8bae1dSRodney W. Grimes 228df8bae1dSRodney W. Grimes /* 229df8bae1dSRodney W. Grimes * Make new vnode reference the null_node. 230df8bae1dSRodney W. Grimes */ 231623ae52eSPoul-Henning Kamp error = null_node_alloc(mp, lowervp, &aliasvp); 232623ae52eSPoul-Henning Kamp if (error) 233df8bae1dSRodney W. Grimes return error; 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes /* 236df8bae1dSRodney W. Grimes * aliasvp is already VREF'd by getnewvnode() 237df8bae1dSRodney W. Grimes */ 238df8bae1dSRodney W. Grimes } 239df8bae1dSRodney W. Grimes 240df8bae1dSRodney W. Grimes vrele(lowervp); 241df8bae1dSRodney W. Grimes 242df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 243df8bae1dSRodney W. Grimes if (lowervp->v_usecount < 1) { 244df8bae1dSRodney W. Grimes /* Should never happen... */ 245623ae52eSPoul-Henning Kamp vprint ("null_node_create: alias ",aliasvp); 246623ae52eSPoul-Henning Kamp vprint ("null_node_create: lower ",lowervp); 247df8bae1dSRodney W. Grimes printf ("null_node_create: lower has 0 usecount.\n"); 248df8bae1dSRodney W. Grimes panic ("null_node_create: lower has 0 usecount."); 249df8bae1dSRodney W. Grimes }; 250df8bae1dSRodney W. Grimes #endif 251df8bae1dSRodney W. Grimes 252df8bae1dSRodney W. Grimes #ifdef NULLFS_DIAGNOSTIC 253df8bae1dSRodney W. Grimes vprint("null_node_create: alias", aliasvp); 254df8bae1dSRodney W. Grimes vprint("null_node_create: lower", lowervp); 255df8bae1dSRodney W. Grimes #endif 256df8bae1dSRodney W. Grimes 257df8bae1dSRodney W. Grimes *newvpp = aliasvp; 258df8bae1dSRodney W. Grimes return (0); 259df8bae1dSRodney W. Grimes } 260df8bae1dSRodney W. Grimes #ifdef NULLFS_DIAGNOSTIC 261df8bae1dSRodney W. Grimes struct vnode * 262df8bae1dSRodney W. Grimes null_checkvp(vp, fil, lno) 263df8bae1dSRodney W. Grimes struct vnode *vp; 264df8bae1dSRodney W. Grimes char *fil; 265df8bae1dSRodney W. Grimes int lno; 266df8bae1dSRodney W. Grimes { 267df8bae1dSRodney W. Grimes struct null_node *a = VTONULL(vp); 268df8bae1dSRodney W. Grimes #ifdef notyet 269df8bae1dSRodney W. Grimes /* 270df8bae1dSRodney W. Grimes * Can't do this check because vop_reclaim runs 271df8bae1dSRodney W. Grimes * with a funny vop vector. 272df8bae1dSRodney W. Grimes */ 273df8bae1dSRodney W. Grimes if (vp->v_op != null_vnodeop_p) { 274df8bae1dSRodney W. Grimes printf ("null_checkvp: on non-null-node\n"); 275df8bae1dSRodney W. Grimes while (null_checkvp_barrier) /*WAIT*/ ; 276df8bae1dSRodney W. Grimes panic("null_checkvp"); 277df8bae1dSRodney W. Grimes }; 278df8bae1dSRodney W. Grimes #endif 279df8bae1dSRodney W. Grimes if (a->null_lowervp == NULL) { 280df8bae1dSRodney W. Grimes /* Should never happen */ 281df8bae1dSRodney W. Grimes int i; u_long *p; 282df8bae1dSRodney W. Grimes printf("vp = %x, ZERO ptr\n", vp); 283df8bae1dSRodney W. Grimes for (p = (u_long *) a, i = 0; i < 8; i++) 284df8bae1dSRodney W. Grimes printf(" %x", p[i]); 285df8bae1dSRodney W. Grimes printf("\n"); 286df8bae1dSRodney W. Grimes /* wait for debugger */ 287df8bae1dSRodney W. Grimes while (null_checkvp_barrier) /*WAIT*/ ; 288df8bae1dSRodney W. Grimes panic("null_checkvp"); 289df8bae1dSRodney W. Grimes } 290df8bae1dSRodney W. Grimes if (a->null_lowervp->v_usecount < 1) { 291df8bae1dSRodney W. Grimes int i; u_long *p; 292df8bae1dSRodney W. Grimes printf("vp = %x, unref'ed lowervp\n", vp); 293df8bae1dSRodney W. Grimes for (p = (u_long *) a, i = 0; i < 8; i++) 294df8bae1dSRodney W. Grimes printf(" %x", p[i]); 295df8bae1dSRodney W. Grimes printf("\n"); 296df8bae1dSRodney W. Grimes /* wait for debugger */ 297df8bae1dSRodney W. Grimes while (null_checkvp_barrier) /*WAIT*/ ; 298df8bae1dSRodney W. Grimes panic ("null with unref'ed lowervp"); 299df8bae1dSRodney W. Grimes }; 300df8bae1dSRodney W. Grimes #ifdef notyet 301df8bae1dSRodney W. Grimes printf("null %x/%d -> %x/%d [%s, %d]\n", 302df8bae1dSRodney W. Grimes NULLTOV(a), NULLTOV(a)->v_usecount, 303df8bae1dSRodney W. Grimes a->null_lowervp, a->null_lowervp->v_usecount, 304df8bae1dSRodney W. Grimes fil, lno); 305df8bae1dSRodney W. Grimes #endif 306df8bae1dSRodney W. Grimes return a->null_lowervp; 307df8bae1dSRodney W. Grimes } 308df8bae1dSRodney W. Grimes #endif 309