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.7 (Berkeley) 5/14/95 37 * 38 * $Id: null_subr.c,v 1.18 1998/07/15 02:32:18 bde Exp $ 39 */ 40 41 #include "opt_debug_nullfs.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/proc.h> 46 #include <sys/vnode.h> 47 #include <sys/mount.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 54 /* 55 * Null layer cache: 56 * Each cache entry holds a reference to the lower vnode 57 * along with a pointer to the alias vnode. When an 58 * entry is added the lower vnode is VREF'd. When the 59 * alias is removed the lower vnode is vrele'd. 60 */ 61 62 #define NULL_NHASH(vp) \ 63 (&null_node_hashtbl[(((uintptr_t)vp)>>LOG2_SIZEVNODE) & null_node_hash]) 64 static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; 65 static u_long null_node_hash; 66 67 static int null_node_alloc __P((struct mount *mp, struct vnode *lowervp, 68 struct vnode **vpp)); 69 static struct vnode * 70 null_node_find __P((struct mount *mp, struct vnode *lowervp)); 71 72 /* 73 * Initialise cache headers 74 */ 75 int 76 nullfs_init(vfsp) 77 struct vfsconf *vfsp; 78 { 79 80 #ifdef NULLFS_DIAGNOSTIC 81 printf("nullfs_init\n"); /* printed during system boot */ 82 #endif 83 null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash); 84 return (0); 85 } 86 87 /* 88 * Return a VREF'ed alias for lower vnode if already exists, else 0. 89 */ 90 static struct vnode * 91 null_node_find(mp, lowervp) 92 struct mount *mp; 93 struct vnode *lowervp; 94 { 95 struct proc *p = curproc; /* XXX */ 96 struct null_node_hashhead *hd; 97 struct null_node *a; 98 struct vnode *vp; 99 100 /* 101 * Find hash base, and then search the (two-way) linked 102 * list looking for a null_node structure which is referencing 103 * the lower vnode. If found, the increment the null_node 104 * reference count (but NOT the lower vnode's VREF counter). 105 */ 106 hd = NULL_NHASH(lowervp); 107 loop: 108 for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) { 109 if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 110 vp = NULLTOV(a); 111 /* 112 * We need vget for the VXLOCK 113 * stuff, but we don't want to lock 114 * the lower node. 115 */ 116 if (vget(vp, 0, p)) { 117 printf ("null_node_find: vget failed.\n"); 118 goto loop; 119 }; 120 return (vp); 121 } 122 } 123 124 return NULLVP; 125 } 126 127 128 /* 129 * Make a new null_node node. 130 * Vp is the alias vnode, lofsvp is the lower vnode. 131 * Maintain a reference to (lowervp). 132 */ 133 static int 134 null_node_alloc(mp, lowervp, vpp) 135 struct mount *mp; 136 struct vnode *lowervp; 137 struct vnode **vpp; 138 { 139 struct null_node_hashhead *hd; 140 struct null_node *xp; 141 struct vnode *othervp, *vp; 142 int error; 143 144 /* 145 * Do the MALLOC before the getnewvnode since doing so afterward 146 * might cause a bogus v_data pointer to get dereferenced 147 * elsewhere if MALLOC should block. 148 */ 149 MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 150 151 error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp); 152 if (error) { 153 FREE(xp, M_TEMP); 154 return (error); 155 } 156 vp = *vpp; 157 158 vp->v_type = lowervp->v_type; 159 xp->null_vnode = vp; 160 vp->v_data = xp; 161 xp->null_lowervp = lowervp; 162 /* 163 * Before we insert our new node onto the hash chains, 164 * check to see if someone else has beaten us to it. 165 * (We could have slept in MALLOC.) 166 */ 167 othervp = null_node_find(mp, lowervp); 168 if (othervp) { 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_NHASH(lowervp); 177 LIST_INSERT_HEAD(hd, xp, null_hash); 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 */ 187 int 188 null_node_create(mp, lowervp, newvpp) 189 struct mount *mp; 190 struct vnode *lowervp; 191 struct vnode **newvpp; 192 { 193 struct vnode *aliasvp; 194 195 aliasvp = null_node_find(mp, lowervp); 196 if (aliasvp) { 197 /* 198 * null_node_find has taken another reference 199 * to the alias vnode. 200 */ 201 #ifdef NULLFS_DIAGNOSTIC 202 vprint("null_node_create: exists", aliasvp); 203 #endif 204 /* VREF(aliasvp); --- done in null_node_find */ 205 } else { 206 int error; 207 208 /* 209 * Get new vnode. 210 */ 211 #ifdef NULLFS_DIAGNOSTIC 212 printf("null_node_create: create new alias vnode\n"); 213 #endif 214 215 /* 216 * Make new vnode reference the null_node. 217 */ 218 error = null_node_alloc(mp, lowervp, &aliasvp); 219 if (error) 220 return error; 221 222 /* 223 * aliasvp is already VREF'd by getnewvnode() 224 */ 225 } 226 227 vrele(lowervp); 228 229 #ifdef DIAGNOSTIC 230 if (lowervp->v_usecount < 1) { 231 /* Should never happen... */ 232 vprint ("null_node_create: alias ", aliasvp); 233 vprint ("null_node_create: lower ", lowervp); 234 panic ("null_node_create: lower has 0 usecount."); 235 }; 236 #endif 237 238 #ifdef NULLFS_DIAGNOSTIC 239 vprint("null_node_create: alias", aliasvp); 240 vprint("null_node_create: lower", lowervp); 241 #endif 242 243 *newvpp = aliasvp; 244 return (0); 245 } 246 247 #ifdef NULLFS_DIAGNOSTIC 248 #include "opt_ddb.h" 249 250 #ifdef DDB 251 #define null_checkvp_barrier 1 252 #else 253 #define null_checkvp_barrier 0 254 #endif 255 256 struct vnode * 257 null_checkvp(vp, fil, lno) 258 struct vnode *vp; 259 char *fil; 260 int lno; 261 { 262 struct null_node *a = VTONULL(vp); 263 #ifdef notyet 264 /* 265 * Can't do this check because vop_reclaim runs 266 * with a funny vop vector. 267 */ 268 if (vp->v_op != null_vnodeop_p) { 269 printf ("null_checkvp: on non-null-node\n"); 270 while (null_checkvp_barrier) /*WAIT*/ ; 271 panic("null_checkvp"); 272 }; 273 #endif 274 if (a->null_lowervp == NULLVP) { 275 /* Should never happen */ 276 int i; u_long *p; 277 printf("vp = %p, ZERO ptr\n", (void *)vp); 278 for (p = (u_long *) a, i = 0; i < 8; i++) 279 printf(" %lx", p[i]); 280 printf("\n"); 281 /* wait for debugger */ 282 while (null_checkvp_barrier) /*WAIT*/ ; 283 panic("null_checkvp"); 284 } 285 if (a->null_lowervp->v_usecount < 1) { 286 int i; u_long *p; 287 printf("vp = %p, unref'ed lowervp\n", (void *)vp); 288 for (p = (u_long *) a, i = 0; i < 8; i++) 289 printf(" %lx", p[i]); 290 printf("\n"); 291 /* wait for debugger */ 292 while (null_checkvp_barrier) /*WAIT*/ ; 293 panic ("null with unref'ed lowervp"); 294 }; 295 #ifdef notyet 296 printf("null %x/%d -> %x/%d [%s, %d]\n", 297 NULLTOV(a), NULLTOV(a)->v_usecount, 298 a->null_lowervp, a->null_lowervp->v_usecount, 299 fil, lno); 300 #endif 301 return a->null_lowervp; 302 } 303 #endif 304