1 /* $NetBSD: layer_subr.c,v 1.9 2001/11/10 13:33:42 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1999 National Aeronautics & Space Administration 5 * All rights reserved. 6 * 7 * This software was written by William Studenmund of the 8 * Numerical Aerospace Simulation Facility, NASA Ames Research Center. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the National Aeronautics & Space Administration 19 * nor the names of its contributors may be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB- 27 * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /* 36 * Copyright (c) 1992, 1993 37 * The Regents of the University of California. All rights reserved. 38 * 39 * This code is derived from software donated to Berkeley by 40 * Jan-Simon Pendry. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * from: Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp 71 * @(#)null_subr.c 8.7 (Berkeley) 5/14/95 72 */ 73 74 #include <sys/cdefs.h> 75 __KERNEL_RCSID(0, "$NetBSD: layer_subr.c,v 1.9 2001/11/10 13:33:42 lukem Exp $"); 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/proc.h> 80 #include <sys/time.h> 81 #include <sys/types.h> 82 #include <sys/vnode.h> 83 #include <sys/mount.h> 84 #include <sys/namei.h> 85 #include <sys/malloc.h> 86 #include <miscfs/specfs/specdev.h> 87 #include <miscfs/genfs/layer.h> 88 #include <miscfs/genfs/layer_extern.h> 89 90 #define NLAYERNODECACHE 16 91 92 /* 93 * layer cache: 94 * Each cache entry holds a reference to the lower vnode 95 * along with a pointer to the alias vnode. When an 96 * entry is added the lower vnode is VREF'd. When the 97 * alias is removed the lower vnode is vrele'd. 98 */ 99 100 /* 101 * Initialise cache headers 102 */ 103 void 104 layerfs_init() 105 { 106 #ifdef LAYERFS_DIAGNOSTIC 107 printf("layerfs_init\n"); /* printed during system boot */ 108 #endif 109 } 110 111 /* 112 * Free global resources of layerfs. 113 */ 114 void 115 layerfs_done() 116 { 117 #ifdef LAYERFS_DIAGNOSTIC 118 printf("layerfs_done\n"); /* printed on layerfs detach */ 119 #endif 120 } 121 122 /* 123 * Return a locked, VREF'ed alias for lower vnode if already exists, else 0. 124 */ 125 struct vnode * 126 layer_node_find(mp, lowervp) 127 struct mount *mp; 128 struct vnode *lowervp; 129 { 130 struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp); 131 struct layer_node_hashhead *hd; 132 struct layer_node *a; 133 struct vnode *vp; 134 135 /* 136 * Find hash base, and then search the (two-way) linked 137 * list looking for a layer_node structure which is referencing 138 * the lower vnode. If found, the increment the layer_node 139 * reference count (but NOT the lower vnode's VREF counter) 140 * and return the vnode locked. 141 */ 142 hd = LAYER_NHASH(lmp, lowervp); 143 loop: 144 simple_lock(&lmp->layerm_hashlock); 145 for (a = hd->lh_first; a != 0; a = a->layer_hash.le_next) { 146 if (a->layer_lowervp == lowervp && LAYERTOV(a)->v_mount == mp) { 147 vp = LAYERTOV(a); 148 simple_unlock(&lmp->layerm_hashlock); 149 /* 150 * We must be careful here as the fact the lower 151 * vnode is locked will imply vp is locked unless 152 * someone has decided to start vclean'ing either 153 * vp or lowervp. 154 * 155 * So we try for an exclusive, recursive lock 156 * on the upper vnode. If it fails, vcleaning 157 * is in progress (so when we try again, we'll 158 * fail). If it succeeds, we now have double 159 * locked the bottom node. So we do an explicit 160 * VOP_UNLOCK on it to keep the counts right. Note 161 * that we will end up with the upper node and 162 * the lower node locked once. 163 */ 164 if (vget(vp, LK_EXCLUSIVE | LK_CANRECURSE)) { 165 printf ("layer_node_find: vget failed.\n"); 166 goto loop; 167 }; 168 VOP_UNLOCK(lowervp, 0); 169 return (vp); 170 } 171 } 172 173 simple_unlock(&lmp->layerm_hashlock); 174 return NULL; 175 } 176 177 178 /* 179 * Make a new layer_node node. 180 * Vp is the alias vnode, lowervp is the lower vnode. 181 * Maintain a reference to lowervp. 182 */ 183 int 184 layer_node_alloc(mp, lowervp, vpp) 185 struct mount *mp; 186 struct vnode *lowervp; 187 struct vnode **vpp; 188 { 189 struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp); 190 struct layer_node_hashhead *hd; 191 struct layer_node *xp; 192 struct vnode *vp, *nvp; 193 int error; 194 extern int (**dead_vnodeop_p) __P((void *)); 195 196 if ((error = getnewvnode(lmp->layerm_tag, mp, lmp->layerm_vnodeop_p, 197 &vp)) != 0) 198 return (error); 199 vp->v_type = lowervp->v_type; 200 vp->v_flag |= VLAYER; 201 202 MALLOC(xp, struct layer_node *, lmp->layerm_size, M_TEMP, M_WAITOK); 203 if (vp->v_type == VBLK || vp->v_type == VCHR) { 204 MALLOC(vp->v_specinfo, struct specinfo *, 205 sizeof(struct specinfo), M_VNODE, M_WAITOK); 206 vp->v_hashchain = NULL; 207 vp->v_rdev = lowervp->v_rdev; 208 } 209 210 vp->v_data = xp; 211 xp->layer_vnode = vp; 212 xp->layer_lowervp = lowervp; 213 xp->layer_flags = 0; 214 /* 215 * Before we insert our new node onto the hash chains, 216 * check to see if someone else has beaten us to it. 217 * (We could have slept in MALLOC.) 218 */ 219 if ((nvp = layer_node_find(mp, lowervp)) != NULL) { 220 *vpp = nvp; 221 222 /* free the substructures we've allocated. */ 223 FREE(xp, M_TEMP); 224 if (vp->v_type == VBLK || vp->v_type == VCHR) 225 FREE(vp->v_specinfo, M_VNODE); 226 227 vp->v_type = VBAD; /* node is discarded */ 228 vp->v_op = dead_vnodeop_p; /* so ops will still work */ 229 vrele(vp); /* get rid of it. */ 230 return (0); 231 } 232 233 simple_lock(&lmp->layerm_hashlock); 234 235 /* 236 * Now lock the new node. We rely on the fact that we were passed 237 * a locked vnode. If the lower node is exporting a struct lock 238 * (v_vnlock != NULL) then we just set the upper v_vnlock to the 239 * lower one, and both are now locked. If the lower node is exporting 240 * NULL, then we copy that up and manually lock the upper node. 241 * 242 * LAYERFS_UPPERLOCK already has the test, so we use it after copying 243 * up the v_vnlock from below. 244 */ 245 246 vp->v_vnlock = lowervp->v_vnlock; 247 LAYERFS_UPPERLOCK(vp, LK_EXCLUSIVE, error); 248 249 if (error) { 250 /* 251 * How did we get a locking error? The node just came off 252 * of the free list, and we're the only routine which 253 * knows it's there... 254 */ 255 vp->v_vnlock = &vp->v_lock; 256 *vpp = NULL; 257 258 /* free the substructures we've allocated. */ 259 FREE(xp, M_TEMP); 260 if (vp->v_type == VBLK || vp->v_type == VCHR) 261 FREE(vp->v_specinfo, M_VNODE); 262 263 vp->v_type = VBAD; /* node is discarded */ 264 vp->v_op = dead_vnodeop_p; /* so ops will still work */ 265 vrele(vp); /* get rid of it. */ 266 return (error); 267 } 268 /* 269 * NetBSD used to do an inlined checkalias here. We do not, as 270 * we never flag device nodes as being aliased. The lowervp 271 * node will, when appropriate, be flaged as an alias. 272 */ 273 274 *vpp = vp; 275 VREF(lowervp); /* Take into account reference held in layer_node */ 276 hd = LAYER_NHASH(lmp, lowervp); 277 LIST_INSERT_HEAD(hd, xp, layer_hash); 278 uvm_vnp_setsize(vp, 0); 279 simple_unlock(&lmp->layerm_hashlock); 280 return (0); 281 } 282 283 284 /* 285 * Try to find an existing layer_node vnode refering 286 * to it, otherwise make a new layer_node vnode which 287 * contains a reference to the lower vnode. 288 * 289 * >>> we assume that the lower node is already locked upon entry, so we 290 * propagate the lock state to upper node << 291 */ 292 int 293 layer_node_create(mp, lowervp, newvpp) 294 struct mount *mp; 295 struct vnode *lowervp; 296 struct vnode **newvpp; 297 { 298 struct vnode *aliasvp; 299 struct layer_mount *lmp = MOUNTTOLAYERMOUNT(mp); 300 301 if ((aliasvp = layer_node_find(mp, lowervp)) != NULL) { 302 /* 303 * layer_node_find has taken another reference 304 * to the alias vnode and moved the lock holding to 305 * aliasvp 306 */ 307 #ifdef LAYERFS_DIAGNOSTIC 308 vprint("layer_node_create: exists", aliasvp); 309 #endif 310 } else { 311 int error; 312 313 /* 314 * Get new vnode. 315 */ 316 #ifdef LAYERFS_DIAGNOSTIC 317 printf("layer_node_create: create new alias vnode\n"); 318 #endif 319 320 /* 321 * Make new vnode reference the layer_node. 322 */ 323 if ((error = (lmp->layerm_alloc)(mp, lowervp, &aliasvp)) != 0) 324 return error; 325 326 /* 327 * aliasvp is already VREF'd by getnewvnode() 328 */ 329 } 330 331 /* 332 * Now that we have VREF'd the upper vnode, release the reference 333 * to the lower node. The existance of the layer_node retains one 334 * reference to the lower node. 335 */ 336 vrele(lowervp); 337 338 #ifdef DIAGNOSTIC 339 if (lowervp->v_usecount < 1) { 340 /* Should never happen... */ 341 vprint("layer_node_create: alias", aliasvp); 342 vprint("layer_node_create: lower", lowervp); 343 panic("layer_node_create: lower has 0 usecount."); 344 }; 345 #endif 346 347 #ifdef LAYERFS_DIAGNOSTIC 348 vprint("layer_node_create: alias", aliasvp); 349 #endif 350 *newvpp = aliasvp; 351 return (0); 352 } 353 354 struct vnode * 355 layer_checkvp(vp, fil, lno) 356 struct vnode *vp; 357 char *fil; 358 int lno; 359 { 360 struct layer_node *a = VTOLAYER(vp); 361 #ifdef notyet 362 /* 363 * Can't do this check because vop_reclaim runs 364 * with a funny vop vector. 365 * 366 * WRS - no it doesnt... 367 */ 368 if (vp->v_op != layer_vnodeop_p) { 369 printf ("layer_checkvp: on non-layer-node\n"); 370 #ifdef notyet 371 while (layer_checkvp_barrier) /*WAIT*/ ; 372 #endif 373 panic("layer_checkvp"); 374 }; 375 #endif 376 if (a->layer_lowervp == NULL) { 377 /* Should never happen */ 378 int i; u_long *p; 379 printf("vp = %p, ZERO ptr\n", vp); 380 for (p = (u_long *) a, i = 0; i < 8; i++) 381 printf(" %lx", p[i]); 382 printf("\n"); 383 /* wait for debugger */ 384 panic("layer_checkvp"); 385 } 386 if (a->layer_lowervp->v_usecount < 1) { 387 int i; u_long *p; 388 printf("vp = %p, unref'ed lowervp\n", vp); 389 for (p = (u_long *) a, i = 0; i < 8; i++) 390 printf(" %lx", p[i]); 391 printf("\n"); 392 /* wait for debugger */ 393 panic ("layer with unref'ed lowervp"); 394 }; 395 #ifdef notnow 396 printf("layer %p/%d -> %p/%d [%s, %d]\n", 397 LAYERTOV(a), LAYERTOV(a)->v_usecount, 398 a->layer_lowervp, a->layer_lowervp->v_usecount, 399 fil, lno); 400 #endif 401 return a->layer_lowervp; 402 } 403