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 * %sccs.include.redist.c% 9 * 10 * @(#)null_subr.c 8.7 (Berkeley) 05/14/95 11 * 12 * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 13 */ 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/proc.h> 18 #include <sys/time.h> 19 #include <sys/types.h> 20 #include <sys/vnode.h> 21 #include <sys/mount.h> 22 #include <sys/namei.h> 23 #include <sys/malloc.h> 24 #include <miscfs/nullfs/null.h> 25 26 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 27 #define NNULLNODECACHE 16 28 29 /* 30 * Null layer cache: 31 * Each cache entry holds a reference to the lower vnode 32 * along with a pointer to the alias vnode. When an 33 * entry is added the lower vnode is VREF'd. When the 34 * alias is removed the lower vnode is vrele'd. 35 */ 36 37 #define NULL_NHASH(vp) \ 38 (&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash]) 39 LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; 40 u_long null_node_hash; 41 42 /* 43 * Initialise cache headers 44 */ 45 nullfs_init() 46 { 47 48 #ifdef NULLFS_DIAGNOSTIC 49 printf("nullfs_init\n"); /* printed during system boot */ 50 #endif 51 null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash); 52 } 53 54 /* 55 * Return a VREF'ed alias for lower vnode if already exists, else 0. 56 */ 57 static struct vnode * 58 null_node_find(mp, lowervp) 59 struct mount *mp; 60 struct vnode *lowervp; 61 { 62 struct proc *p = curproc; /* XXX */ 63 struct null_node_hashhead *hd; 64 struct null_node *a; 65 struct vnode *vp; 66 67 /* 68 * Find hash base, and then search the (two-way) linked 69 * list looking for a null_node structure which is referencing 70 * the lower vnode. If found, the increment the null_node 71 * reference count (but NOT the lower vnode's VREF counter). 72 */ 73 hd = NULL_NHASH(lowervp); 74 loop: 75 for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) { 76 if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 77 vp = NULLTOV(a); 78 /* 79 * We need vget for the VXLOCK 80 * stuff, but we don't want to lock 81 * the lower node. 82 */ 83 if (vget(vp, 0, p)) { 84 printf ("null_node_find: vget failed.\n"); 85 goto loop; 86 }; 87 return (vp); 88 } 89 } 90 91 return NULL; 92 } 93 94 95 /* 96 * Make a new null_node node. 97 * Vp is the alias vnode, lofsvp is the lower vnode. 98 * Maintain a reference to (lowervp). 99 */ 100 static int 101 null_node_alloc(mp, lowervp, vpp) 102 struct mount *mp; 103 struct vnode *lowervp; 104 struct vnode **vpp; 105 { 106 struct null_node_hashhead *hd; 107 struct null_node *xp; 108 struct vnode *othervp, *vp; 109 int error; 110 111 if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp)) 112 return (error); 113 vp = *vpp; 114 115 MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK); 116 vp->v_type = lowervp->v_type; 117 xp->null_vnode = vp; 118 vp->v_data = xp; 119 xp->null_lowervp = lowervp; 120 /* 121 * Before we insert our new node onto the hash chains, 122 * check to see if someone else has beaten us to it. 123 * (We could have slept in MALLOC.) 124 */ 125 if (othervp = null_node_find(lowervp)) { 126 FREE(xp, M_TEMP); 127 vp->v_type = VBAD; /* node is discarded */ 128 vp->v_usecount = 0; /* XXX */ 129 *vpp = othervp; 130 return 0; 131 }; 132 VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */ 133 hd = NULL_NHASH(lowervp); 134 LIST_INSERT_HEAD(hd, xp, null_hash); 135 return 0; 136 } 137 138 139 /* 140 * Try to find an existing null_node vnode refering 141 * to it, otherwise make a new null_node vnode which 142 * contains a reference to the lower vnode. 143 */ 144 int 145 null_node_create(mp, lowervp, newvpp) 146 struct mount *mp; 147 struct vnode *lowervp; 148 struct vnode **newvpp; 149 { 150 struct vnode *aliasvp; 151 152 if (aliasvp = null_node_find(mp, lowervp)) { 153 /* 154 * null_node_find has taken another reference 155 * to the alias vnode. 156 */ 157 #ifdef NULLFS_DIAGNOSTIC 158 vprint("null_node_create: exists", NULLTOV(ap)); 159 #endif 160 /* VREF(aliasvp); --- done in null_node_find */ 161 } else { 162 int error; 163 164 /* 165 * Get new vnode. 166 */ 167 #ifdef NULLFS_DIAGNOSTIC 168 printf("null_node_create: create new alias vnode\n"); 169 #endif 170 171 /* 172 * Make new vnode reference the null_node. 173 */ 174 if (error = null_node_alloc(mp, lowervp, &aliasvp)) 175 return error; 176 177 /* 178 * aliasvp is already VREF'd by getnewvnode() 179 */ 180 } 181 182 vrele(lowervp); 183 184 #ifdef DIAGNOSTIC 185 if (lowervp->v_usecount < 1) { 186 /* Should never happen... */ 187 vprint ("null_node_create: alias ", aliasvp); 188 vprint ("null_node_create: lower ", lowervp); 189 panic ("null_node_create: lower has 0 usecount."); 190 }; 191 #endif 192 193 #ifdef NULLFS_DIAGNOSTIC 194 vprint("null_node_create: alias", aliasvp); 195 vprint("null_node_create: lower", lowervp); 196 #endif 197 198 *newvpp = aliasvp; 199 return (0); 200 } 201 #ifdef NULLFS_DIAGNOSTIC 202 struct vnode * 203 null_checkvp(vp, fil, lno) 204 struct vnode *vp; 205 char *fil; 206 int lno; 207 { 208 struct null_node *a = VTONULL(vp); 209 #ifdef notyet 210 /* 211 * Can't do this check because vop_reclaim runs 212 * with a funny vop vector. 213 */ 214 if (vp->v_op != null_vnodeop_p) { 215 printf ("null_checkvp: on non-null-node\n"); 216 while (null_checkvp_barrier) /*WAIT*/ ; 217 panic("null_checkvp"); 218 }; 219 #endif 220 if (a->null_lowervp == NULL) { 221 /* Should never happen */ 222 int i; u_long *p; 223 printf("vp = %x, ZERO ptr\n", vp); 224 for (p = (u_long *) a, i = 0; i < 8; i++) 225 printf(" %x", p[i]); 226 printf("\n"); 227 /* wait for debugger */ 228 while (null_checkvp_barrier) /*WAIT*/ ; 229 panic("null_checkvp"); 230 } 231 if (a->null_lowervp->v_usecount < 1) { 232 int i; u_long *p; 233 printf("vp = %x, unref'ed lowervp\n", vp); 234 for (p = (u_long *) a, i = 0; i < 8; i++) 235 printf(" %x", p[i]); 236 printf("\n"); 237 /* wait for debugger */ 238 while (null_checkvp_barrier) /*WAIT*/ ; 239 panic ("null with unref'ed lowervp"); 240 }; 241 #ifdef notyet 242 printf("null %x/%d -> %x/%d [%s, %d]\n", 243 NULLTOV(a), NULLTOV(a)->v_usecount, 244 a->null_lowervp, a->null_lowervp->v_usecount, 245 fil, lno); 246 #endif 247 return a->null_lowervp; 248 } 249 #endif 250