xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 67716)
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*67716Smckusick  *	@(#)null_subr.c	8.6 (Berkeley) 08/20/94
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>
1754751Sjohnh #include <sys/time.h>
1854751Sjohnh #include <sys/types.h>
1954751Sjohnh #include <sys/vnode.h>
2054751Sjohnh #include <sys/mount.h>
2154751Sjohnh #include <sys/namei.h>
2254751Sjohnh #include <sys/malloc.h>
2355025Smckusick #include <miscfs/nullfs/null.h>
2454751Sjohnh 
2554751Sjohnh #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
2654754Sjohnh #define	NNULLNODECACHE 16
2754751Sjohnh 
2854751Sjohnh /*
2954754Sjohnh  * Null layer cache:
3054938Sheideman  * Each cache entry holds a reference to the lower vnode
3154751Sjohnh  * along with a pointer to the alias vnode.  When an
3254938Sheideman  * entry is added the lower vnode is VREF'd.  When the
3354938Sheideman  * alias is removed the lower vnode is vrele'd.
3454751Sjohnh  */
3554751Sjohnh 
36*67716Smckusick #define	NULL_NHASH(vp) \
37*67716Smckusick 	(&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash])
38*67716Smckusick LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
39*67716Smckusick u_long null_node_hash;
4054751Sjohnh 
4154751Sjohnh /*
4254751Sjohnh  * Initialise cache headers
4354751Sjohnh  */
4454754Sjohnh nullfs_init()
4554751Sjohnh {
46*67716Smckusick 
4754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
4854754Sjohnh 	printf("nullfs_init\n");		/* printed during system boot */
4954751Sjohnh #endif
50*67716Smckusick 	null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash);
5154751Sjohnh }
5254751Sjohnh 
5354751Sjohnh /*
5454938Sheideman  * Return a VREF'ed alias for lower vnode if already exists, else 0.
5554938Sheideman  */
5654938Sheideman static struct vnode *
5754938Sheideman null_node_find(mp, lowervp)
5854751Sjohnh 	struct mount *mp;
5954938Sheideman 	struct vnode *lowervp;
6054751Sjohnh {
61*67716Smckusick 	struct null_node_hashhead *hd;
6254754Sjohnh 	struct null_node *a;
6354938Sheideman 	struct vnode *vp;
6454751Sjohnh 
6554751Sjohnh 	/*
6654751Sjohnh 	 * Find hash base, and then search the (two-way) linked
6754754Sjohnh 	 * list looking for a null_node structure which is referencing
6854938Sheideman 	 * the lower vnode.  If found, the increment the null_node
6954938Sheideman 	 * reference count (but NOT the lower vnode's VREF counter).
7054751Sjohnh 	 */
71*67716Smckusick 	hd = NULL_NHASH(lowervp);
7254938Sheideman loop:
73*67716Smckusick 	for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) {
7454938Sheideman 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
7554938Sheideman 			vp = NULLTOV(a);
7654938Sheideman 			/*
7754951Sheideman 			 * We need vget for the VXLOCK
7854951Sheideman 			 * stuff, but we don't want to lock
7954951Sheideman 			 * the lower node.
8054938Sheideman 			 */
8165245Smckusick 			if (vget(vp, 0)) {
8254938Sheideman 				printf ("null_node_find: vget failed.\n");
8354938Sheideman 				goto loop;
8454938Sheideman 			};
8554938Sheideman 			return (vp);
8654751Sjohnh 		}
8754751Sjohnh 	}
8854751Sjohnh 
8954938Sheideman 	return NULL;
9054751Sjohnh }
9154751Sjohnh 
9254938Sheideman 
9354766Sjohnh /*
9454951Sheideman  * Make a new null_node node.
9554951Sheideman  * Vp is the alias vnode, lofsvp is the lower vnode.
9654951Sheideman  * Maintain a reference to (lowervp).
9754951Sheideman  */
9854951Sheideman static int
9954951Sheideman null_node_alloc(mp, lowervp, vpp)
10054951Sheideman 	struct mount *mp;
10154951Sheideman 	struct vnode *lowervp;
10254951Sheideman 	struct vnode **vpp;
10354951Sheideman {
104*67716Smckusick 	struct null_node_hashhead *hd;
10554951Sheideman 	struct null_node *xp;
10654951Sheideman 	struct vnode *othervp, *vp;
10754951Sheideman 	int error;
10854951Sheideman 
10965424Spendry 	if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
11065424Spendry 		return (error);
11154951Sheideman 	vp = *vpp;
11254951Sheideman 
11354951Sheideman 	MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
11454951Sheideman 	vp->v_type = lowervp->v_type;
11554951Sheideman 	xp->null_vnode = vp;
11654951Sheideman 	vp->v_data = xp;
11754951Sheideman 	xp->null_lowervp = lowervp;
11854951Sheideman 	/*
11954951Sheideman 	 * Before we insert our new node onto the hash chains,
12054951Sheideman 	 * check to see if someone else has beaten us to it.
12154951Sheideman 	 * (We could have slept in MALLOC.)
12254951Sheideman 	 */
12354951Sheideman 	if (othervp = null_node_find(lowervp)) {
12454951Sheideman 		FREE(xp, M_TEMP);
12554951Sheideman 		vp->v_type = VBAD;	/* node is discarded */
12654951Sheideman 		vp->v_usecount = 0;	/* XXX */
12754951Sheideman 		*vpp = othervp;
12854951Sheideman 		return 0;
12954951Sheideman 	};
13054951Sheideman 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
131*67716Smckusick 	hd = NULL_NHASH(lowervp);
132*67716Smckusick 	LIST_INSERT_HEAD(hd, xp, null_hash);
13354951Sheideman 	return 0;
13454951Sheideman }
13554951Sheideman 
13654951Sheideman 
13754951Sheideman /*
13854766Sjohnh  * Try to find an existing null_node vnode refering
13954766Sjohnh  * to it, otherwise make a new null_node vnode which
14054938Sheideman  * contains a reference to the lower vnode.
14154766Sjohnh  */
14254766Sjohnh int
14354938Sheideman null_node_create(mp, lowervp, newvpp)
14454751Sjohnh 	struct mount *mp;
14554938Sheideman 	struct vnode *lowervp;
14654751Sjohnh 	struct vnode **newvpp;
14754751Sjohnh {
14854751Sjohnh 	struct vnode *aliasvp;
14954751Sjohnh 
15054938Sheideman 	if (aliasvp = null_node_find(mp, lowervp)) {
15154751Sjohnh 		/*
15254938Sheideman 		 * null_node_find has taken another reference
15354938Sheideman 		 * to the alias vnode.
15454751Sjohnh 		 */
15554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
15654938Sheideman 		vprint("null_node_create: exists", NULLTOV(ap));
15754751Sjohnh #endif
15854938Sheideman 		/* VREF(aliasvp); --- done in null_node_find */
15954751Sjohnh 	} else {
16054751Sjohnh 		int error;
16154751Sjohnh 
16254751Sjohnh 		/*
16354751Sjohnh 		 * Get new vnode.
16454751Sjohnh 		 */
16554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
16654938Sheideman 		printf("null_node_create: create new alias vnode\n");
16754751Sjohnh #endif
16854751Sjohnh 
16954751Sjohnh 		/*
17054754Sjohnh 		 * Make new vnode reference the null_node.
17154751Sjohnh 		 */
17254951Sheideman 		if (error = null_node_alloc(mp, lowervp, &aliasvp))
17354951Sheideman 			return error;
17454751Sjohnh 
17554751Sjohnh 		/*
17654751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
17754751Sjohnh 		 */
17854751Sjohnh 	}
17954751Sjohnh 
18054938Sheideman 	vrele(lowervp);
18154751Sjohnh 
18254951Sheideman #ifdef DIAGNOSTIC
18354938Sheideman 	if (lowervp->v_usecount < 1) {
18454951Sheideman 		/* Should never happen... */
18567398Smkm 		vprint ("null_node_create: alias ", aliasvp);
18667398Smkm 		vprint ("null_node_create: lower ", lowervp);
18754938Sheideman 		panic ("null_node_create: lower has 0 usecount.");
18854938Sheideman 	};
18954951Sheideman #endif
19054938Sheideman 
19154754Sjohnh #ifdef NULLFS_DIAGNOSTIC
19254938Sheideman 	vprint("null_node_create: alias", aliasvp);
19354938Sheideman 	vprint("null_node_create: lower", lowervp);
19454751Sjohnh #endif
19554751Sjohnh 
19654751Sjohnh 	*newvpp = aliasvp;
19754751Sjohnh 	return (0);
19854751Sjohnh }
19954754Sjohnh #ifdef NULLFS_DIAGNOSTIC
20054751Sjohnh struct vnode *
20154754Sjohnh null_checkvp(vp, fil, lno)
20254751Sjohnh 	struct vnode *vp;
20354751Sjohnh 	char *fil;
20454751Sjohnh 	int lno;
20554751Sjohnh {
20654938Sheideman 	struct null_node *a = VTONULL(vp);
20755025Smckusick #ifdef notyet
20854938Sheideman 	/*
20954938Sheideman 	 * Can't do this check because vop_reclaim runs
21054938Sheideman 	 * with a funny vop vector.
21154938Sheideman 	 */
21254938Sheideman 	if (vp->v_op != null_vnodeop_p) {
21354938Sheideman 		printf ("null_checkvp: on non-null-node\n");
21454938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
21554938Sheideman 		panic("null_checkvp");
21654938Sheideman 	};
21754938Sheideman #endif
21854938Sheideman 	if (a->null_lowervp == NULL) {
21954766Sjohnh 		/* Should never happen */
22054751Sjohnh 		int i; u_long *p;
22154751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
22254751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
22354751Sjohnh 			printf(" %x", p[i]);
22454751Sjohnh 		printf("\n");
22554938Sheideman 		/* wait for debugger */
22654938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
22754754Sjohnh 		panic("null_checkvp");
22854751Sjohnh 	}
22954938Sheideman 	if (a->null_lowervp->v_usecount < 1) {
23054938Sheideman 		int i; u_long *p;
23154938Sheideman 		printf("vp = %x, unref'ed lowervp\n", vp);
23254938Sheideman 		for (p = (u_long *) a, i = 0; i < 8; i++)
23354938Sheideman 			printf(" %x", p[i]);
23454938Sheideman 		printf("\n");
23554938Sheideman 		/* wait for debugger */
23654938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
23754938Sheideman 		panic ("null with unref'ed lowervp");
23854938Sheideman 	};
23955025Smckusick #ifdef notyet
24054938Sheideman 	printf("null %x/%d -> %x/%d [%s, %d]\n",
24154938Sheideman 	        NULLTOV(a), NULLTOV(a)->v_usecount,
24254766Sjohnh 		a->null_lowervp, a->null_lowervp->v_usecount,
24354751Sjohnh 		fil, lno);
24454938Sheideman #endif
24554754Sjohnh 	return a->null_lowervp;
24654751Sjohnh }
24754751Sjohnh #endif
248