null_subr.c revision 12595
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: null_subr.c,v 1.4 1995/12/03 14:38:49 bde Exp $ 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 51extern int nullfs_init __P((void)); 52 53#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 54#define NNULLNODECACHE 16 55#define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1)) 56 57/* 58 * Null layer cache: 59 * Each cache entry holds a reference to the lower vnode 60 * along with a pointer to the alias vnode. When an 61 * entry is added the lower vnode is VREF'd. When the 62 * alias is removed the lower vnode is vrele'd. 63 */ 64 65/* 66 * Cache head 67 */ 68struct null_node_cache { 69 struct null_node *ac_forw; 70 struct null_node *ac_back; 71}; 72 73static struct null_node_cache null_node_cache[NNULLNODECACHE]; 74 75static int null_node_alloc __P((struct mount *mp, struct vnode *lowervp, 76 struct vnode **vpp)); 77static struct vnode * 78 null_node_find __P((struct mount *mp, struct vnode *lowervp)); 79static struct null_node_cache * 80 null_node_hash __P((struct vnode *lowervp)); 81 82/* 83 * Initialise cache headers 84 */ 85int 86nullfs_init() 87{ 88 struct null_node_cache *ac; 89#ifdef NULLFS_DIAGNOSTIC 90 printf("nullfs_init\n"); /* printed during system boot */ 91#endif 92 93 for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) 94 ac->ac_forw = ac->ac_back = (struct null_node *) ac; 95 return (0); 96} 97 98/* 99 * Compute hash list for given lower vnode 100 */ 101static struct null_node_cache * 102null_node_hash(lowervp) 103struct vnode *lowervp; 104{ 105 106 return (&null_node_cache[NULL_NHASH(lowervp)]); 107} 108 109/* 110 * Return a VREF'ed alias for lower vnode if already exists, else 0. 111 */ 112static struct vnode * 113null_node_find(mp, lowervp) 114 struct mount *mp; 115 struct vnode *lowervp; 116{ 117 struct null_node_cache *hd; 118 struct null_node *a; 119 struct vnode *vp; 120 121 /* 122 * Find hash base, and then search the (two-way) linked 123 * list looking for a null_node structure which is referencing 124 * the lower vnode. If found, the increment the null_node 125 * reference count (but NOT the lower vnode's VREF counter). 126 */ 127 hd = null_node_hash(lowervp); 128loop: 129 for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) { 130 if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 131 vp = NULLTOV(a); 132 /* 133 * We need vget for the VXLOCK 134 * stuff, but we don't want to lock 135 * the lower node. 136 */ 137 if (vget(vp, 0)) { 138 printf ("null_node_find: vget failed.\n"); 139 goto loop; 140 }; 141 return (vp); 142 } 143 } 144 145 return NULL; 146} 147 148 149/* 150 * Make a new null_node node. 151 * Vp is the alias vnode, lofsvp is the lower vnode. 152 * Maintain a reference to (lowervp). 153 */ 154static int 155null_node_alloc(mp, lowervp, vpp) 156 struct mount *mp; 157 struct vnode *lowervp; 158 struct vnode **vpp; 159{ 160 struct null_node_cache *hd; 161 struct null_node *xp; 162 struct vnode *othervp, *vp; 163 int error; 164 165 error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp); 166 if (error) 167 return (error); 168 vp = *vpp; 169 170 MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 171 vp->v_type = lowervp->v_type; 172 xp->null_vnode = vp; 173 vp->v_data = xp; 174 xp->null_lowervp = lowervp; 175 /* 176 * Before we insert our new node onto the hash chains, 177 * check to see if someone else has beaten us to it. 178 * (We could have slept in MALLOC.) 179 */ 180 othervp = null_node_find(mp, lowervp); 181 if (othervp) { 182 FREE(xp, M_TEMP); 183 vp->v_type = VBAD; /* node is discarded */ 184 vp->v_usecount = 0; /* XXX */ 185 *vpp = othervp; 186 return 0; 187 }; 188 VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 189 hd = null_node_hash(lowervp); 190 insque(xp, hd); 191 return 0; 192} 193 194 195/* 196 * Try to find an existing null_node vnode refering 197 * to it, otherwise make a new null_node vnode which 198 * contains a reference to the lower vnode. 199 */ 200int 201null_node_create(mp, lowervp, newvpp) 202 struct mount *mp; 203 struct vnode *lowervp; 204 struct vnode **newvpp; 205{ 206 struct vnode *aliasvp; 207 208 aliasvp = null_node_find(mp, lowervp); 209 if (aliasvp) { 210 /* 211 * null_node_find has taken another reference 212 * to the alias vnode. 213 */ 214#ifdef NULLFS_DIAGNOSTIC 215 vprint("null_node_create: exists", NULLTOV(ap)); 216#endif 217 /* VREF(aliasvp); --- done in null_node_find */ 218 } else { 219 int error; 220 221 /* 222 * Get new vnode. 223 */ 224#ifdef NULLFS_DIAGNOSTIC 225 printf("null_node_create: create new alias vnode\n"); 226#endif 227 228 /* 229 * Make new vnode reference the null_node. 230 */ 231 error = null_node_alloc(mp, lowervp, &aliasvp); 232 if (error) 233 return error; 234 235 /* 236 * aliasvp is already VREF'd by getnewvnode() 237 */ 238 } 239 240 vrele(lowervp); 241 242#ifdef DIAGNOSTIC 243 if (lowervp->v_usecount < 1) { 244 /* Should never happen... */ 245 vprint ("null_node_create: alias ",aliasvp); 246 vprint ("null_node_create: lower ",lowervp); 247 printf ("null_node_create: lower has 0 usecount.\n"); 248 panic ("null_node_create: lower has 0 usecount."); 249 }; 250#endif 251 252#ifdef NULLFS_DIAGNOSTIC 253 vprint("null_node_create: alias", aliasvp); 254 vprint("null_node_create: lower", lowervp); 255#endif 256 257 *newvpp = aliasvp; 258 return (0); 259} 260#ifdef NULLFS_DIAGNOSTIC 261struct vnode * 262null_checkvp(vp, fil, lno) 263 struct vnode *vp; 264 char *fil; 265 int lno; 266{ 267 struct null_node *a = VTONULL(vp); 268#ifdef notyet 269 /* 270 * Can't do this check because vop_reclaim runs 271 * with a funny vop vector. 272 */ 273 if (vp->v_op != null_vnodeop_p) { 274 printf ("null_checkvp: on non-null-node\n"); 275 while (null_checkvp_barrier) /*WAIT*/ ; 276 panic("null_checkvp"); 277 }; 278#endif 279 if (a->null_lowervp == NULL) { 280 /* Should never happen */ 281 int i; u_long *p; 282 printf("vp = %x, ZERO ptr\n", vp); 283 for (p = (u_long *) a, i = 0; i < 8; i++) 284 printf(" %x", p[i]); 285 printf("\n"); 286 /* wait for debugger */ 287 while (null_checkvp_barrier) /*WAIT*/ ; 288 panic("null_checkvp"); 289 } 290 if (a->null_lowervp->v_usecount < 1) { 291 int i; u_long *p; 292 printf("vp = %x, unref'ed lowervp\n", vp); 293 for (p = (u_long *) a, i = 0; i < 8; i++) 294 printf(" %x", p[i]); 295 printf("\n"); 296 /* wait for debugger */ 297 while (null_checkvp_barrier) /*WAIT*/ ; 298 panic ("null with unref'ed lowervp"); 299 }; 300#ifdef notyet 301 printf("null %x/%d -> %x/%d [%s, %d]\n", 302 NULLTOV(a), NULLTOV(a)->v_usecount, 303 a->null_lowervp, a->null_lowervp->v_usecount, 304 fil, lno); 305#endif 306 return a->null_lowervp; 307} 308#endif 309