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.5 1995/12/03 14:54:22 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 51 extern 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 */ 68 struct null_node_cache { 69 struct null_node *ac_forw; 70 struct null_node *ac_back; 71 }; 72 73 static struct null_node_cache null_node_cache[NNULLNODECACHE]; 74 75 static int null_node_alloc __P((struct mount *mp, struct vnode *lowervp, 76 struct vnode **vpp)); 77 static struct vnode * 78 null_node_find __P((struct mount *mp, struct vnode *lowervp)); 79 static struct null_node_cache * 80 null_node_hash __P((struct vnode *lowervp)); 81 82 /* 83 * Initialise cache headers 84 */ 85 int 86 nullfs_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 */ 101 static struct null_node_cache * 102 null_node_hash(lowervp) 103 struct 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 */ 112 static struct vnode * 113 null_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); 128 loop: 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 */ 154 static int 155 null_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 /* 166 * Do the MALLOC before the getnewvnode since doing so afterward 167 * might cause a bogus v_data pointer to get dereferenced 168 * elsewhere if MALLOC should block. 169 */ 170 MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 171 172 error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp); 173 if (error) { 174 FREE(xp, M_TEMP); 175 return (error); 176 } 177 vp = *vpp; 178 179 vp->v_type = lowervp->v_type; 180 xp->null_vnode = vp; 181 vp->v_data = xp; 182 xp->null_lowervp = lowervp; 183 /* 184 * Before we insert our new node onto the hash chains, 185 * check to see if someone else has beaten us to it. 186 * (We could have slept in MALLOC.) 187 */ 188 othervp = null_node_find(mp, lowervp); 189 if (othervp) { 190 FREE(xp, M_TEMP); 191 vp->v_type = VBAD; /* node is discarded */ 192 vp->v_usecount = 0; /* XXX */ 193 *vpp = othervp; 194 return 0; 195 }; 196 VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 197 hd = null_node_hash(lowervp); 198 insque(xp, hd); 199 return 0; 200 } 201 202 203 /* 204 * Try to find an existing null_node vnode refering 205 * to it, otherwise make a new null_node vnode which 206 * contains a reference to the lower vnode. 207 */ 208 int 209 null_node_create(mp, lowervp, newvpp) 210 struct mount *mp; 211 struct vnode *lowervp; 212 struct vnode **newvpp; 213 { 214 struct vnode *aliasvp; 215 216 aliasvp = null_node_find(mp, lowervp); 217 if (aliasvp) { 218 /* 219 * null_node_find has taken another reference 220 * to the alias vnode. 221 */ 222 #ifdef NULLFS_DIAGNOSTIC 223 vprint("null_node_create: exists", NULLTOV(ap)); 224 #endif 225 /* VREF(aliasvp); --- done in null_node_find */ 226 } else { 227 int error; 228 229 /* 230 * Get new vnode. 231 */ 232 #ifdef NULLFS_DIAGNOSTIC 233 printf("null_node_create: create new alias vnode\n"); 234 #endif 235 236 /* 237 * Make new vnode reference the null_node. 238 */ 239 error = null_node_alloc(mp, lowervp, &aliasvp); 240 if (error) 241 return error; 242 243 /* 244 * aliasvp is already VREF'd by getnewvnode() 245 */ 246 } 247 248 vrele(lowervp); 249 250 #ifdef DIAGNOSTIC 251 if (lowervp->v_usecount < 1) { 252 /* Should never happen... */ 253 vprint ("null_node_create: alias ",aliasvp); 254 vprint ("null_node_create: lower ",lowervp); 255 printf ("null_node_create: lower has 0 usecount.\n"); 256 panic ("null_node_create: lower has 0 usecount."); 257 }; 258 #endif 259 260 #ifdef NULLFS_DIAGNOSTIC 261 vprint("null_node_create: alias", aliasvp); 262 vprint("null_node_create: lower", lowervp); 263 #endif 264 265 *newvpp = aliasvp; 266 return (0); 267 } 268 #ifdef NULLFS_DIAGNOSTIC 269 struct vnode * 270 null_checkvp(vp, fil, lno) 271 struct vnode *vp; 272 char *fil; 273 int lno; 274 { 275 struct null_node *a = VTONULL(vp); 276 #ifdef notyet 277 /* 278 * Can't do this check because vop_reclaim runs 279 * with a funny vop vector. 280 */ 281 if (vp->v_op != null_vnodeop_p) { 282 printf ("null_checkvp: on non-null-node\n"); 283 while (null_checkvp_barrier) /*WAIT*/ ; 284 panic("null_checkvp"); 285 }; 286 #endif 287 if (a->null_lowervp == NULL) { 288 /* Should never happen */ 289 int i; u_long *p; 290 printf("vp = %x, ZERO ptr\n", vp); 291 for (p = (u_long *) a, i = 0; i < 8; i++) 292 printf(" %x", p[i]); 293 printf("\n"); 294 /* wait for debugger */ 295 while (null_checkvp_barrier) /*WAIT*/ ; 296 panic("null_checkvp"); 297 } 298 if (a->null_lowervp->v_usecount < 1) { 299 int i; u_long *p; 300 printf("vp = %x, unref'ed lowervp\n", vp); 301 for (p = (u_long *) a, i = 0; i < 8; i++) 302 printf(" %x", p[i]); 303 printf("\n"); 304 /* wait for debugger */ 305 while (null_checkvp_barrier) /*WAIT*/ ; 306 panic ("null with unref'ed lowervp"); 307 }; 308 #ifdef notyet 309 printf("null %x/%d -> %x/%d [%s, %d]\n", 310 NULLTOV(a), NULLTOV(a)->v_usecount, 311 a->null_lowervp, a->null_lowervp->v_usecount, 312 fil, lno); 313 #endif 314 return a->null_lowervp; 315 } 316 #endif 317