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