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