xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 69438)
154751Sjohnh /*
263245Sbostic  * Copyright (c) 1992, 1993
363245Sbostic  *	The Regents of the University of California.  All rights reserved.
454751Sjohnh  *
554751Sjohnh  * This code is derived from software donated to Berkeley by
654751Sjohnh  * Jan-Simon Pendry.
754751Sjohnh  *
854751Sjohnh  * %sccs.include.redist.c%
954751Sjohnh  *
10*69438Smckusick  *	@(#)null_subr.c	8.7 (Berkeley) 05/14/95
1154751Sjohnh  *
1254751Sjohnh  * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
1354751Sjohnh  */
1454751Sjohnh 
1554751Sjohnh #include <sys/param.h>
1654751Sjohnh #include <sys/systm.h>
17*69438Smckusick #include <sys/proc.h>
1854751Sjohnh #include <sys/time.h>
1954751Sjohnh #include <sys/types.h>
2054751Sjohnh #include <sys/vnode.h>
2154751Sjohnh #include <sys/mount.h>
2254751Sjohnh #include <sys/namei.h>
2354751Sjohnh #include <sys/malloc.h>
2455025Smckusick #include <miscfs/nullfs/null.h>
2554751Sjohnh 
2654751Sjohnh #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
2754754Sjohnh #define	NNULLNODECACHE 16
2854751Sjohnh 
2954751Sjohnh /*
3054754Sjohnh  * Null layer cache:
3154938Sheideman  * Each cache entry holds a reference to the lower vnode
3254751Sjohnh  * along with a pointer to the alias vnode.  When an
3354938Sheideman  * entry is added the lower vnode is VREF'd.  When the
3454938Sheideman  * alias is removed the lower vnode is vrele'd.
3554751Sjohnh  */
3654751Sjohnh 
3767716Smckusick #define	NULL_NHASH(vp) \
3867716Smckusick 	(&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash])
LIST_HEAD(null_node_hashhead,null_node)3967716Smckusick LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
4067716Smckusick u_long null_node_hash;
4154751Sjohnh 
4254751Sjohnh /*
4354751Sjohnh  * Initialise cache headers
4454751Sjohnh  */
4554754Sjohnh nullfs_init()
4654751Sjohnh {
4767716Smckusick 
4854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
4954754Sjohnh 	printf("nullfs_init\n");		/* printed during system boot */
5054751Sjohnh #endif
5167716Smckusick 	null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash);
5254751Sjohnh }
5354751Sjohnh 
5454751Sjohnh /*
5554938Sheideman  * Return a VREF'ed alias for lower vnode if already exists, else 0.
5654938Sheideman  */
5754938Sheideman static struct vnode *
null_node_find(mp,lowervp)5854938Sheideman null_node_find(mp, lowervp)
5954751Sjohnh 	struct mount *mp;
6054938Sheideman 	struct vnode *lowervp;
6154751Sjohnh {
62*69438Smckusick 	struct proc *p = curproc;	/* XXX */
6367716Smckusick 	struct null_node_hashhead *hd;
6454754Sjohnh 	struct null_node *a;
6554938Sheideman 	struct vnode *vp;
6654751Sjohnh 
6754751Sjohnh 	/*
6854751Sjohnh 	 * Find hash base, and then search the (two-way) linked
6954754Sjohnh 	 * list looking for a null_node structure which is referencing
7054938Sheideman 	 * the lower vnode.  If found, the increment the null_node
7154938Sheideman 	 * reference count (but NOT the lower vnode's VREF counter).
7254751Sjohnh 	 */
7367716Smckusick 	hd = NULL_NHASH(lowervp);
7454938Sheideman loop:
7567716Smckusick 	for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) {
7654938Sheideman 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
7754938Sheideman 			vp = NULLTOV(a);
7854938Sheideman 			/*
7954951Sheideman 			 * We need vget for the VXLOCK
8054951Sheideman 			 * stuff, but we don't want to lock
8154951Sheideman 			 * the lower node.
8254938Sheideman 			 */
83*69438Smckusick 			if (vget(vp, 0, p)) {
8454938Sheideman 				printf ("null_node_find: vget failed.\n");
8554938Sheideman 				goto loop;
8654938Sheideman 			};
8754938Sheideman 			return (vp);
8854751Sjohnh 		}
8954751Sjohnh 	}
9054751Sjohnh 
9154938Sheideman 	return NULL;
9254751Sjohnh }
9354751Sjohnh 
9454938Sheideman 
9554766Sjohnh /*
9654951Sheideman  * Make a new null_node node.
9754951Sheideman  * Vp is the alias vnode, lofsvp is the lower vnode.
9854951Sheideman  * Maintain a reference to (lowervp).
9954951Sheideman  */
10054951Sheideman static int
null_node_alloc(mp,lowervp,vpp)10154951Sheideman null_node_alloc(mp, lowervp, vpp)
10254951Sheideman 	struct mount *mp;
10354951Sheideman 	struct vnode *lowervp;
10454951Sheideman 	struct vnode **vpp;
10554951Sheideman {
10667716Smckusick 	struct null_node_hashhead *hd;
10754951Sheideman 	struct null_node *xp;
10854951Sheideman 	struct vnode *othervp, *vp;
10954951Sheideman 	int error;
11054951Sheideman 
11165424Spendry 	if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
11265424Spendry 		return (error);
11354951Sheideman 	vp = *vpp;
11454951Sheideman 
11554951Sheideman 	MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
11654951Sheideman 	vp->v_type = lowervp->v_type;
11754951Sheideman 	xp->null_vnode = vp;
11854951Sheideman 	vp->v_data = xp;
11954951Sheideman 	xp->null_lowervp = lowervp;
12054951Sheideman 	/*
12154951Sheideman 	 * Before we insert our new node onto the hash chains,
12254951Sheideman 	 * check to see if someone else has beaten us to it.
12354951Sheideman 	 * (We could have slept in MALLOC.)
12454951Sheideman 	 */
12554951Sheideman 	if (othervp = null_node_find(lowervp)) {
12654951Sheideman 		FREE(xp, M_TEMP);
12754951Sheideman 		vp->v_type = VBAD;	/* node is discarded */
12854951Sheideman 		vp->v_usecount = 0;	/* XXX */
12954951Sheideman 		*vpp = othervp;
13054951Sheideman 		return 0;
13154951Sheideman 	};
13254951Sheideman 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
13367716Smckusick 	hd = NULL_NHASH(lowervp);
13467716Smckusick 	LIST_INSERT_HEAD(hd, xp, null_hash);
13554951Sheideman 	return 0;
13654951Sheideman }
13754951Sheideman 
13854951Sheideman 
13954951Sheideman /*
14054766Sjohnh  * Try to find an existing null_node vnode refering
14154766Sjohnh  * to it, otherwise make a new null_node vnode which
14254938Sheideman  * contains a reference to the lower vnode.
14354766Sjohnh  */
14454766Sjohnh int
null_node_create(mp,lowervp,newvpp)14554938Sheideman null_node_create(mp, lowervp, newvpp)
14654751Sjohnh 	struct mount *mp;
14754938Sheideman 	struct vnode *lowervp;
14854751Sjohnh 	struct vnode **newvpp;
14954751Sjohnh {
15054751Sjohnh 	struct vnode *aliasvp;
15154751Sjohnh 
15254938Sheideman 	if (aliasvp = null_node_find(mp, lowervp)) {
15354751Sjohnh 		/*
15454938Sheideman 		 * null_node_find has taken another reference
15554938Sheideman 		 * to the alias vnode.
15654751Sjohnh 		 */
15754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
15854938Sheideman 		vprint("null_node_create: exists", NULLTOV(ap));
15954751Sjohnh #endif
16054938Sheideman 		/* VREF(aliasvp); --- done in null_node_find */
16154751Sjohnh 	} else {
16254751Sjohnh 		int error;
16354751Sjohnh 
16454751Sjohnh 		/*
16554751Sjohnh 		 * Get new vnode.
16654751Sjohnh 		 */
16754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
16854938Sheideman 		printf("null_node_create: create new alias vnode\n");
16954751Sjohnh #endif
17054751Sjohnh 
17154751Sjohnh 		/*
17254754Sjohnh 		 * Make new vnode reference the null_node.
17354751Sjohnh 		 */
17454951Sheideman 		if (error = null_node_alloc(mp, lowervp, &aliasvp))
17554951Sheideman 			return error;
17654751Sjohnh 
17754751Sjohnh 		/*
17854751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
17954751Sjohnh 		 */
18054751Sjohnh 	}
18154751Sjohnh 
18254938Sheideman 	vrele(lowervp);
18354751Sjohnh 
18454951Sheideman #ifdef DIAGNOSTIC
18554938Sheideman 	if (lowervp->v_usecount < 1) {
18654951Sheideman 		/* Should never happen... */
18767398Smkm 		vprint ("null_node_create: alias ", aliasvp);
18867398Smkm 		vprint ("null_node_create: lower ", lowervp);
18954938Sheideman 		panic ("null_node_create: lower has 0 usecount.");
19054938Sheideman 	};
19154951Sheideman #endif
19254938Sheideman 
19354754Sjohnh #ifdef NULLFS_DIAGNOSTIC
19454938Sheideman 	vprint("null_node_create: alias", aliasvp);
19554938Sheideman 	vprint("null_node_create: lower", lowervp);
19654751Sjohnh #endif
19754751Sjohnh 
19854751Sjohnh 	*newvpp = aliasvp;
19954751Sjohnh 	return (0);
20054751Sjohnh }
20154754Sjohnh #ifdef NULLFS_DIAGNOSTIC
20254751Sjohnh struct vnode *
null_checkvp(vp,fil,lno)20354754Sjohnh null_checkvp(vp, fil, lno)
20454751Sjohnh 	struct vnode *vp;
20554751Sjohnh 	char *fil;
20654751Sjohnh 	int lno;
20754751Sjohnh {
20854938Sheideman 	struct null_node *a = VTONULL(vp);
20955025Smckusick #ifdef notyet
21054938Sheideman 	/*
21154938Sheideman 	 * Can't do this check because vop_reclaim runs
21254938Sheideman 	 * with a funny vop vector.
21354938Sheideman 	 */
21454938Sheideman 	if (vp->v_op != null_vnodeop_p) {
21554938Sheideman 		printf ("null_checkvp: on non-null-node\n");
21654938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
21754938Sheideman 		panic("null_checkvp");
21854938Sheideman 	};
21954938Sheideman #endif
22054938Sheideman 	if (a->null_lowervp == NULL) {
22154766Sjohnh 		/* Should never happen */
22254751Sjohnh 		int i; u_long *p;
22354751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
22454751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
22554751Sjohnh 			printf(" %x", p[i]);
22654751Sjohnh 		printf("\n");
22754938Sheideman 		/* wait for debugger */
22854938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
22954754Sjohnh 		panic("null_checkvp");
23054751Sjohnh 	}
23154938Sheideman 	if (a->null_lowervp->v_usecount < 1) {
23254938Sheideman 		int i; u_long *p;
23354938Sheideman 		printf("vp = %x, unref'ed lowervp\n", vp);
23454938Sheideman 		for (p = (u_long *) a, i = 0; i < 8; i++)
23554938Sheideman 			printf(" %x", p[i]);
23654938Sheideman 		printf("\n");
23754938Sheideman 		/* wait for debugger */
23854938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
23954938Sheideman 		panic ("null with unref'ed lowervp");
24054938Sheideman 	};
24155025Smckusick #ifdef notyet
24254938Sheideman 	printf("null %x/%d -> %x/%d [%s, %d]\n",
24354938Sheideman 	        NULLTOV(a), NULLTOV(a)->v_usecount,
24454766Sjohnh 		a->null_lowervp, a->null_lowervp->v_usecount,
24554751Sjohnh 		fil, lno);
24654938Sheideman #endif
24754754Sjohnh 	return a->null_lowervp;
24854751Sjohnh }
24954751Sjohnh #endif
250