xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 67398)
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*67398Smkm  *	@(#)null_subr.c	8.5 (Berkeley) 06/15/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
2754754Sjohnh #define	NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1))
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 
3754751Sjohnh /*
3854751Sjohnh  * Cache head
3954751Sjohnh  */
4054754Sjohnh struct null_node_cache {
4154754Sjohnh 	struct null_node	*ac_forw;
4254754Sjohnh 	struct null_node	*ac_back;
4354751Sjohnh };
4454751Sjohnh 
4554754Sjohnh static struct null_node_cache null_node_cache[NNULLNODECACHE];
4654751Sjohnh 
4754751Sjohnh /*
4854751Sjohnh  * Initialise cache headers
4954751Sjohnh  */
5054754Sjohnh nullfs_init()
5154751Sjohnh {
5254754Sjohnh 	struct null_node_cache *ac;
5354754Sjohnh #ifdef NULLFS_DIAGNOSTIC
5454754Sjohnh 	printf("nullfs_init\n");		/* printed during system boot */
5554751Sjohnh #endif
5654751Sjohnh 
5754754Sjohnh 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++)
5854754Sjohnh 		ac->ac_forw = ac->ac_back = (struct null_node *) ac;
5954751Sjohnh }
6054751Sjohnh 
6154751Sjohnh /*
6254938Sheideman  * Compute hash list for given lower vnode
6354751Sjohnh  */
6454754Sjohnh static struct null_node_cache *
6554938Sheideman null_node_hash(lowervp)
6654938Sheideman struct vnode *lowervp;
6754751Sjohnh {
6854951Sheideman 
6954938Sheideman 	return (&null_node_cache[NULL_NHASH(lowervp)]);
7054751Sjohnh }
7154751Sjohnh 
7254766Sjohnh /*
7354938Sheideman  * Return a VREF'ed alias for lower vnode if already exists, else 0.
7454938Sheideman  */
7554938Sheideman static struct vnode *
7654938Sheideman null_node_find(mp, lowervp)
7754751Sjohnh 	struct mount *mp;
7854938Sheideman 	struct vnode *lowervp;
7954751Sjohnh {
8054754Sjohnh 	struct null_node_cache *hd;
8154754Sjohnh 	struct null_node *a;
8254938Sheideman 	struct vnode *vp;
8354751Sjohnh 
8454751Sjohnh 	/*
8554751Sjohnh 	 * Find hash base, and then search the (two-way) linked
8654754Sjohnh 	 * list looking for a null_node structure which is referencing
8754938Sheideman 	 * the lower vnode.  If found, the increment the null_node
8854938Sheideman 	 * reference count (but NOT the lower vnode's VREF counter).
8954751Sjohnh 	 */
9054938Sheideman 	hd = null_node_hash(lowervp);
9154938Sheideman loop:
9254754Sjohnh 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
9354938Sheideman 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
9454938Sheideman 			vp = NULLTOV(a);
9554938Sheideman 			/*
9654951Sheideman 			 * We need vget for the VXLOCK
9754951Sheideman 			 * stuff, but we don't want to lock
9854951Sheideman 			 * the lower node.
9954938Sheideman 			 */
10065245Smckusick 			if (vget(vp, 0)) {
10154938Sheideman 				printf ("null_node_find: vget failed.\n");
10254938Sheideman 				goto loop;
10354938Sheideman 			};
10454938Sheideman 			return (vp);
10554751Sjohnh 		}
10654751Sjohnh 	}
10754751Sjohnh 
10854938Sheideman 	return NULL;
10954751Sjohnh }
11054751Sjohnh 
11154938Sheideman 
11254766Sjohnh /*
11354951Sheideman  * Make a new null_node node.
11454951Sheideman  * Vp is the alias vnode, lofsvp is the lower vnode.
11554951Sheideman  * Maintain a reference to (lowervp).
11654951Sheideman  */
11754951Sheideman static int
11854951Sheideman null_node_alloc(mp, lowervp, vpp)
11954951Sheideman 	struct mount *mp;
12054951Sheideman 	struct vnode *lowervp;
12154951Sheideman 	struct vnode **vpp;
12254951Sheideman {
12354951Sheideman 	struct null_node_cache *hd;
12454951Sheideman 	struct null_node *xp;
12554951Sheideman 	struct vnode *othervp, *vp;
12654951Sheideman 	int error;
12754951Sheideman 
12865424Spendry 	if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
12965424Spendry 		return (error);
13054951Sheideman 	vp = *vpp;
13154951Sheideman 
13254951Sheideman 	MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
13354951Sheideman 	vp->v_type = lowervp->v_type;
13454951Sheideman 	xp->null_vnode = vp;
13554951Sheideman 	vp->v_data = xp;
13654951Sheideman 	xp->null_lowervp = lowervp;
13754951Sheideman 	/*
13854951Sheideman 	 * Before we insert our new node onto the hash chains,
13954951Sheideman 	 * check to see if someone else has beaten us to it.
14054951Sheideman 	 * (We could have slept in MALLOC.)
14154951Sheideman 	 */
14254951Sheideman 	if (othervp = null_node_find(lowervp)) {
14354951Sheideman 		FREE(xp, M_TEMP);
14454951Sheideman 		vp->v_type = VBAD;	/* node is discarded */
14554951Sheideman 		vp->v_usecount = 0;	/* XXX */
14654951Sheideman 		*vpp = othervp;
14754951Sheideman 		return 0;
14854951Sheideman 	};
14954951Sheideman 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
15054951Sheideman 	hd = null_node_hash(lowervp);
15154951Sheideman 	insque(xp, hd);
15254951Sheideman 	return 0;
15354951Sheideman }
15454951Sheideman 
15554951Sheideman 
15654951Sheideman /*
15754766Sjohnh  * Try to find an existing null_node vnode refering
15854766Sjohnh  * to it, otherwise make a new null_node vnode which
15954938Sheideman  * contains a reference to the lower vnode.
16054766Sjohnh  */
16154766Sjohnh int
16254938Sheideman null_node_create(mp, lowervp, newvpp)
16354751Sjohnh 	struct mount *mp;
16454938Sheideman 	struct vnode *lowervp;
16554751Sjohnh 	struct vnode **newvpp;
16654751Sjohnh {
16754751Sjohnh 	struct vnode *aliasvp;
16854751Sjohnh 
16954938Sheideman 	if (aliasvp = null_node_find(mp, lowervp)) {
17054751Sjohnh 		/*
17154938Sheideman 		 * null_node_find has taken another reference
17254938Sheideman 		 * to the alias vnode.
17354751Sjohnh 		 */
17454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
17554938Sheideman 		vprint("null_node_create: exists", NULLTOV(ap));
17654751Sjohnh #endif
17754938Sheideman 		/* VREF(aliasvp); --- done in null_node_find */
17854751Sjohnh 	} else {
17954751Sjohnh 		int error;
18054751Sjohnh 
18154751Sjohnh 		/*
18254751Sjohnh 		 * Get new vnode.
18354751Sjohnh 		 */
18454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
18554938Sheideman 		printf("null_node_create: create new alias vnode\n");
18654751Sjohnh #endif
18754751Sjohnh 
18854751Sjohnh 		/*
18954754Sjohnh 		 * Make new vnode reference the null_node.
19054751Sjohnh 		 */
19154951Sheideman 		if (error = null_node_alloc(mp, lowervp, &aliasvp))
19254951Sheideman 			return error;
19354751Sjohnh 
19454751Sjohnh 		/*
19554751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
19654751Sjohnh 		 */
19754751Sjohnh 	}
19854751Sjohnh 
19954938Sheideman 	vrele(lowervp);
20054751Sjohnh 
20154951Sheideman #ifdef DIAGNOSTIC
20254938Sheideman 	if (lowervp->v_usecount < 1) {
20354951Sheideman 		/* Should never happen... */
204*67398Smkm 		vprint ("null_node_create: alias ", aliasvp);
205*67398Smkm 		vprint ("null_node_create: lower ", lowervp);
20654938Sheideman 		panic ("null_node_create: lower has 0 usecount.");
20754938Sheideman 	};
20854951Sheideman #endif
20954938Sheideman 
21054754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21154938Sheideman 	vprint("null_node_create: alias", aliasvp);
21254938Sheideman 	vprint("null_node_create: lower", lowervp);
21354751Sjohnh #endif
21454751Sjohnh 
21554751Sjohnh 	*newvpp = aliasvp;
21654751Sjohnh 	return (0);
21754751Sjohnh }
21854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21954751Sjohnh struct vnode *
22054754Sjohnh null_checkvp(vp, fil, lno)
22154751Sjohnh 	struct vnode *vp;
22254751Sjohnh 	char *fil;
22354751Sjohnh 	int lno;
22454751Sjohnh {
22554938Sheideman 	struct null_node *a = VTONULL(vp);
22655025Smckusick #ifdef notyet
22754938Sheideman 	/*
22854938Sheideman 	 * Can't do this check because vop_reclaim runs
22954938Sheideman 	 * with a funny vop vector.
23054938Sheideman 	 */
23154938Sheideman 	if (vp->v_op != null_vnodeop_p) {
23254938Sheideman 		printf ("null_checkvp: on non-null-node\n");
23354938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
23454938Sheideman 		panic("null_checkvp");
23554938Sheideman 	};
23654938Sheideman #endif
23754938Sheideman 	if (a->null_lowervp == NULL) {
23854766Sjohnh 		/* Should never happen */
23954751Sjohnh 		int i; u_long *p;
24054751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
24154751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
24254751Sjohnh 			printf(" %x", p[i]);
24354751Sjohnh 		printf("\n");
24454938Sheideman 		/* wait for debugger */
24554938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
24654754Sjohnh 		panic("null_checkvp");
24754751Sjohnh 	}
24854938Sheideman 	if (a->null_lowervp->v_usecount < 1) {
24954938Sheideman 		int i; u_long *p;
25054938Sheideman 		printf("vp = %x, unref'ed lowervp\n", vp);
25154938Sheideman 		for (p = (u_long *) a, i = 0; i < 8; i++)
25254938Sheideman 			printf(" %x", p[i]);
25354938Sheideman 		printf("\n");
25454938Sheideman 		/* wait for debugger */
25554938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
25654938Sheideman 		panic ("null with unref'ed lowervp");
25754938Sheideman 	};
25855025Smckusick #ifdef notyet
25954938Sheideman 	printf("null %x/%d -> %x/%d [%s, %d]\n",
26054938Sheideman 	        NULLTOV(a), NULLTOV(a)->v_usecount,
26154766Sjohnh 		a->null_lowervp, a->null_lowervp->v_usecount,
26254751Sjohnh 		fil, lno);
26354938Sheideman #endif
26454754Sjohnh 	return a->null_lowervp;
26554751Sjohnh }
26654751Sjohnh #endif
267