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