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