File:  [DragonFly] / src / sys / vfs / nullfs / Attic / null_subr.c
Revision 1.8: download - view: text, annotated - select for diffs
Wed Apr 21 16:55:09 2004 UTC (10 years, 6 months ago) by cpressey
Branches: MAIN
CVS tags: HEAD
Style(9) cleanup to src/sys/vfs, stage 12/21: nullfs.

- Convert K&R-style function definitions to ANSI style.

Submitted-by: Andre Nathan <andre@digirati.com.br>
Additional-reformatting-by: cpressey

    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: src/sys/miscfs/nullfs/null_subr.c,v 1.21.2.4 2001/06/26 04:20:09 bp Exp $
   39:  * $DragonFly: src/sys/vfs/nullfs/null_subr.c,v 1.8 2004/04/21 16:55:09 cpressey Exp $
   40:  */
   41: 
   42: #include <sys/param.h>
   43: #include <sys/systm.h>
   44: #include <sys/kernel.h>
   45: #include <sys/proc.h>
   46: #include <sys/vnode.h>
   47: #include <sys/mount.h>
   48: #include <sys/malloc.h>
   49: #include "null.h"
   50: 
   51: #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
   52: #define	NNULLNODECACHE 16
   53: 
   54: /*
   55:  * Null layer cache:
   56:  * Each cache entry holds a reference to the lower vnode
   57:  * along with a pointer to the alias vnode.  When an
   58:  * entry is added the lower vnode is VREF'd.  When the
   59:  * alias is removed the lower vnode is vrele'd.
   60:  */
   61: 
   62: #define	NULL_NHASH(vp) \
   63: 	(&null_node_hashtbl[(((uintptr_t)vp)>>LOG2_SIZEVNODE) & null_node_hash])
   64: 
   65: static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
   66: static u_long null_node_hash;
   67: struct lock null_hashlock;
   68: 
   69: static MALLOC_DEFINE(M_NULLFSHASH, "NULLFS hash", "NULLFS hash table");
   70: MALLOC_DEFINE(M_NULLFSNODE, "NULLFS node", "NULLFS vnode private part");
   71: 
   72: static int	null_node_alloc(struct mount *mp, struct vnode *lowervp,
   73: 				     struct vnode **vpp);
   74: static struct vnode *
   75: 		null_node_find(struct mount *mp, struct vnode *lowervp);
   76: 
   77: /*
   78:  * Initialise cache headers
   79:  */
   80: int
   81: nullfs_init(struct vfsconf *vfsp)
   82: {
   83: 	NULLFSDEBUG("nullfs_init\n");		/* printed during system boot */
   84: 	null_node_hashtbl = hashinit(NNULLNODECACHE, M_NULLFSHASH, &null_node_hash);
   85: 	lockinit(&null_hashlock, 0, "nullhs", 0, 0);
   86: 	return (0);
   87: }
   88: 
   89: int
   90: nullfs_uninit(struct vfsconf *vfsp)
   91: {
   92:         if (null_node_hashtbl) {
   93: 		free(null_node_hashtbl, M_NULLFSHASH);
   94: 	}
   95: 	return (0);
   96: }
   97: 
   98: /*
   99:  * Return a VREF'ed alias for lower vnode if already exists, else 0.
  100:  * Lower vnode should be locked on entry and will be left locked on exit.
  101:  */
  102: static struct vnode *
  103: null_node_find(struct mount *mp, struct vnode *lowervp)
  104: {
  105: 	struct thread *td = curthread;	/* XXX */
  106: 	struct null_node_hashhead *hd;
  107: 	struct null_node *a;
  108: 	struct vnode *vp;
  109: 
  110: 	/*
  111: 	 * Find hash base, and then search the (two-way) linked
  112: 	 * list looking for a null_node structure which is referencing
  113: 	 * the lower vnode.  If found, the increment the null_node
  114: 	 * reference count (but NOT the lower vnode's VREF counter).
  115: 	 */
  116: 	hd = NULL_NHASH(lowervp);
  117: loop:
  118: 	lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, td);
  119: 	LIST_FOREACH(a, hd, null_hash) {
  120: 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
  121: 			vp = NULLTOV(a);
  122: 			lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
  123: 			/*
  124: 			 * We need vget for the VXLOCK
  125: 			 * stuff, but we don't want to lock
  126: 			 * the lower node.
  127: 			 */
  128: 			if (vget(vp, NULL, LK_EXCLUSIVE | LK_CANRECURSE, td)) {
  129: 				printf ("null_node_find: vget failed.\n");
  130: 				goto loop;
  131: 			}
  132: 			VOP_UNLOCK(lowervp, NULL, 0, td);
  133: 			return (vp);
  134: 		}
  135: 	}
  136: 	lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
  137: 
  138: 	return NULLVP;
  139: }
  140: 
  141: 
  142: /*
  143:  * Make a new null_node node.
  144:  * Vp is the alias vnode, lofsvp is the lower vnode.
  145:  * Maintain a reference to (lowervp).
  146:  */
  147: static int
  148: null_node_alloc(struct mount *mp, struct vnode *lowervp, struct vnode **vpp)
  149: {
  150: 	struct thread *td = curthread;	/* XXX */
  151: 	struct null_node_hashhead *hd;
  152: 	struct null_node *xp;
  153: 	struct vnode *othervp, *vp;
  154: 	int error;
  155: 
  156: 	/*
  157: 	 * Do the MALLOC before the getnewvnode since doing so afterward
  158: 	 * might cause a bogus v_data pointer to get dereferenced
  159: 	 * elsewhere if MALLOC should block.
  160: 	 */
  161: 	MALLOC(xp, struct null_node *, sizeof(struct null_node),
  162: 	    M_NULLFSNODE, M_WAITOK);
  163: 
  164: 	error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp);
  165: 	if (error) {
  166: 		FREE(xp, M_NULLFSNODE);
  167: 		return (error);
  168: 	}
  169: 	vp = *vpp;
  170: 
  171: 	vp->v_type = lowervp->v_type;
  172: 
  173: 	/*
  174: 	 * XXX:
  175: 	 * When nullfs encounters sockets or device nodes, it
  176: 	 * has a hard time working with the normal vp union.
  177: 	 * This still needs to be investigated.
  178: 	 */
  179: 	if (vp->v_type == VCHR || vp->v_type == VBLK)
  180: 		addalias(vp, lowervp->v_un.vu_spec.vu_specinfo);
  181: 	else
  182: 		vp->v_un = lowervp->v_un;
  183: 	lockinit(&xp->null_lock, 0, "nullnode", 0, LK_CANRECURSE);
  184: 	xp->null_vnode = vp;
  185: 	vp->v_data = xp;
  186: 	xp->null_lowervp = lowervp;
  187: 	/*
  188: 	 * Before we insert our new node onto the hash chains,
  189: 	 * check to see if someone else has beaten us to it.
  190: 	 * (We could have slept in MALLOC.)
  191: 	 */
  192: 	othervp = null_node_find(mp, lowervp);
  193: 	if (othervp) {
  194: 		vp->v_data = NULL;
  195: 		FREE(xp, M_NULLFSNODE);
  196: 		vp->v_type = VBAD;	/* node is discarded */
  197: 		vrele(vp);
  198: 		*vpp = othervp;
  199: 		return 0;
  200: 	}
  201: 
  202: 	/*
  203: 	 * From NetBSD:
  204: 	 * Now lock the new node. We rely on the fact that we were passed
  205: 	 * a locked vnode. If the lower node is exporting a struct lock
  206: 	 * (v_vnlock != NULL) then we just set the upper v_vnlock to the
  207: 	 * lower one, and both are now locked. If the lower node is exporting
  208: 	 * NULL, then we copy that up and manually lock the new vnode.
  209: 	 */
  210: 
  211: 	lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, td);
  212: 	vp->v_vnlock = lowervp->v_vnlock;
  213: 	error = VOP_LOCK(vp, NULL, LK_EXCLUSIVE | LK_THISLAYER, td);
  214: 	if (error)
  215: 		panic("null_node_alloc: can't lock new vnode\n");
  216: 
  217: 	VREF(lowervp);
  218: 	hd = NULL_NHASH(lowervp);
  219: 	LIST_INSERT_HEAD(hd, xp, null_hash);
  220: 	lockmgr(&null_hashlock, LK_RELEASE, NULL, td);
  221: 	return 0;
  222: }
  223: 
  224: 
  225: /*
  226:  * Try to find an existing null_node vnode refering to the given underlying
  227:  * vnode (which should be locked). If no vnode found, create a new null_node
  228:  * vnode which contains a reference to the lower vnode.
  229:  */
  230: int
  231: null_node_create(struct mount *mp, struct vnode *lowervp, struct vnode **newvpp)
  232: {
  233: 	struct vnode *aliasvp;
  234: 
  235: 	aliasvp = null_node_find(mp, lowervp);
  236: 	if (aliasvp) {
  237: 		/*
  238: 		 * null_node_find has taken another reference
  239: 		 * to the alias vnode.
  240: 		 */
  241: 		vrele(lowervp);
  242: #ifdef NULLFS_DEBUG
  243: 		vprint("null_node_create: exists", aliasvp);
  244: #endif
  245: 	} else {
  246: 		int error;
  247: 
  248: 		/*
  249: 		 * Get new vnode.
  250: 		 */
  251: 		NULLFSDEBUG("null_node_create: create new alias vnode\n");
  252: 
  253: 		/*
  254: 		 * Make new vnode reference the null_node.
  255: 		 */
  256: 		error = null_node_alloc(mp, lowervp, &aliasvp);
  257: 		if (error)
  258: 			return error;
  259: 
  260: 		/*
  261: 		 * aliasvp is already VREF'd by getnewvnode()
  262: 		 */
  263: 	}
  264: 
  265: #ifdef DIAGNOSTIC
  266: 	if (lowervp->v_usecount < 1) {
  267: 		/* Should never happen... */
  268: 		vprint ("null_node_create: alias ", aliasvp);
  269: 		vprint ("null_node_create: lower ", lowervp);
  270: 		panic ("null_node_create: lower has 0 usecount.");
  271: 	};
  272: #endif
  273: 
  274: #ifdef NULLFS_DEBUG
  275: 	vprint("null_node_create: alias", aliasvp);
  276: 	vprint("null_node_create: lower", lowervp);
  277: #endif
  278: 
  279: 	*newvpp = aliasvp;
  280: 	return (0);
  281: }
  282: 
  283: #ifdef DIAGNOSTIC
  284: #include "opt_ddb.h"
  285: 
  286: #ifdef DDB
  287: #define	null_checkvp_barrier	1
  288: #else
  289: #define	null_checkvp_barrier	0
  290: #endif
  291: 
  292: struct vnode *
  293: null_checkvp(struct vnode *vp, char *fil, int lno)
  294: {
  295: 	struct null_node *a = VTONULL(vp);
  296: #ifdef notyet
  297: 	/*
  298: 	 * Can't do this check because vop_reclaim runs
  299: 	 * with a funny vop vector.
  300: 	 */
  301: 	if (vp->v_op != null_vnodeop_p) {
  302: 		printf ("null_checkvp: on non-null-node\n");
  303: 		while (null_checkvp_barrier) /*WAIT*/ ;
  304: 		panic("null_checkvp");
  305: 	};
  306: #endif
  307: 	if (a->null_lowervp == NULLVP) {
  308: 		/* Should never happen */
  309: 		int i; u_long *p;
  310: 		printf("vp = %p, ZERO ptr\n", (void *)vp);
  311: 		for (p = (u_long *) a, i = 0; i < 8; i++)
  312: 			printf(" %lx", p[i]);
  313: 		printf("\n");
  314: 		/* wait for debugger */
  315: 		while (null_checkvp_barrier) /*WAIT*/ ;
  316: 		panic("null_checkvp");
  317: 	}
  318: 	if (a->null_lowervp->v_usecount < 1) {
  319: 		int i; u_long *p;
  320: 		printf("vp = %p, unref'ed lowervp\n", (void *)vp);
  321: 		for (p = (u_long *) a, i = 0; i < 8; i++)
  322: 			printf(" %lx", p[i]);
  323: 		printf("\n");
  324: 		/* wait for debugger */
  325: 		while (null_checkvp_barrier) /*WAIT*/ ;
  326: 		panic ("null with unref'ed lowervp");
  327: 	};
  328: #ifdef notyet
  329: 	printf("null %x/%d -> %x/%d [%s, %d]\n",
  330: 	        NULLTOV(a), NULLTOV(a)->v_usecount,
  331: 		a->null_lowervp, a->null_lowervp->v_usecount,
  332: 		fil, lno);
  333: #endif
  334: 	return a->null_lowervp;
  335: }
  336: #endif