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