xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 65424)
154751Sjohnh /*
263245Sbostic  * Copyright (c) 1992, 1993
363245Sbostic  *	The Regents of the University of California.  All rights reserved.
454751Sjohnh  * All rights reserved.
554751Sjohnh  *
654751Sjohnh  * This code is derived from software donated to Berkeley by
754751Sjohnh  * Jan-Simon Pendry.
854751Sjohnh  *
954751Sjohnh  * %sccs.include.redist.c%
1054751Sjohnh  *
11*65424Spendry  *	@(#)null_subr.c	8.3 (Berkeley) 01/04/94
1254751Sjohnh  *
1354751Sjohnh  * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
1454751Sjohnh  */
1554751Sjohnh 
1654751Sjohnh #include <sys/param.h>
1754751Sjohnh #include <sys/systm.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
2854754Sjohnh #define	NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1))
2954751Sjohnh 
3054751Sjohnh /*
3154754Sjohnh  * Null layer cache:
3254938Sheideman  * Each cache entry holds a reference to the lower vnode
3354751Sjohnh  * along with a pointer to the alias vnode.  When an
3454938Sheideman  * entry is added the lower vnode is VREF'd.  When the
3554938Sheideman  * alias is removed the lower vnode is vrele'd.
3654751Sjohnh  */
3754751Sjohnh 
3854751Sjohnh /*
3954751Sjohnh  * Cache head
4054751Sjohnh  */
4154754Sjohnh struct null_node_cache {
4254754Sjohnh 	struct null_node	*ac_forw;
4354754Sjohnh 	struct null_node	*ac_back;
4454751Sjohnh };
4554751Sjohnh 
4654754Sjohnh static struct null_node_cache null_node_cache[NNULLNODECACHE];
4754751Sjohnh 
4854751Sjohnh /*
4954751Sjohnh  * Initialise cache headers
5054751Sjohnh  */
5154754Sjohnh nullfs_init()
5254751Sjohnh {
5354754Sjohnh 	struct null_node_cache *ac;
5454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
5554754Sjohnh 	printf("nullfs_init\n");		/* printed during system boot */
5654751Sjohnh #endif
5754751Sjohnh 
5854754Sjohnh 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++)
5954754Sjohnh 		ac->ac_forw = ac->ac_back = (struct null_node *) ac;
6054751Sjohnh }
6154751Sjohnh 
6254751Sjohnh /*
6354938Sheideman  * Compute hash list for given lower vnode
6454751Sjohnh  */
6554754Sjohnh static struct null_node_cache *
6654938Sheideman null_node_hash(lowervp)
6754938Sheideman struct vnode *lowervp;
6854751Sjohnh {
6954951Sheideman 
7054938Sheideman 	return (&null_node_cache[NULL_NHASH(lowervp)]);
7154751Sjohnh }
7254751Sjohnh 
7354766Sjohnh /*
7454938Sheideman  * Return a VREF'ed alias for lower vnode if already exists, else 0.
7554938Sheideman  */
7654938Sheideman static struct vnode *
7754938Sheideman null_node_find(mp, lowervp)
7854751Sjohnh 	struct mount *mp;
7954938Sheideman 	struct vnode *lowervp;
8054751Sjohnh {
8154754Sjohnh 	struct null_node_cache *hd;
8254754Sjohnh 	struct null_node *a;
8354938Sheideman 	struct vnode *vp;
8454751Sjohnh 
8554751Sjohnh 	/*
8654751Sjohnh 	 * Find hash base, and then search the (two-way) linked
8754754Sjohnh 	 * list looking for a null_node structure which is referencing
8854938Sheideman 	 * the lower vnode.  If found, the increment the null_node
8954938Sheideman 	 * reference count (but NOT the lower vnode's VREF counter).
9054751Sjohnh 	 */
9154938Sheideman 	hd = null_node_hash(lowervp);
9254938Sheideman loop:
9354754Sjohnh 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
9454938Sheideman 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
9554938Sheideman 			vp = NULLTOV(a);
9654938Sheideman 			/*
9754951Sheideman 			 * We need vget for the VXLOCK
9854951Sheideman 			 * stuff, but we don't want to lock
9954951Sheideman 			 * the lower node.
10054938Sheideman 			 */
10165245Smckusick 			if (vget(vp, 0)) {
10254938Sheideman 				printf ("null_node_find: vget failed.\n");
10354938Sheideman 				goto loop;
10454938Sheideman 			};
10554938Sheideman 			return (vp);
10654751Sjohnh 		}
10754751Sjohnh 	}
10854751Sjohnh 
10954938Sheideman 	return NULL;
11054751Sjohnh }
11154751Sjohnh 
11254938Sheideman 
11354766Sjohnh /*
11454951Sheideman  * Make a new null_node node.
11554951Sheideman  * Vp is the alias vnode, lofsvp is the lower vnode.
11654951Sheideman  * Maintain a reference to (lowervp).
11754951Sheideman  */
11854951Sheideman static int
11954951Sheideman null_node_alloc(mp, lowervp, vpp)
12054951Sheideman 	struct mount *mp;
12154951Sheideman 	struct vnode *lowervp;
12254951Sheideman 	struct vnode **vpp;
12354951Sheideman {
12454951Sheideman 	struct null_node_cache *hd;
12554951Sheideman 	struct null_node *xp;
12654951Sheideman 	struct vnode *othervp, *vp;
12754951Sheideman 	int error;
12854951Sheideman 
129*65424Spendry 	if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
130*65424Spendry 		return (error);
13154951Sheideman 	vp = *vpp;
13254951Sheideman 
13354951Sheideman 	MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
13454951Sheideman 	vp->v_type = lowervp->v_type;
13554951Sheideman 	xp->null_vnode = vp;
13654951Sheideman 	vp->v_data = xp;
13754951Sheideman 	xp->null_lowervp = lowervp;
13854951Sheideman 	/*
13954951Sheideman 	 * Before we insert our new node onto the hash chains,
14054951Sheideman 	 * check to see if someone else has beaten us to it.
14154951Sheideman 	 * (We could have slept in MALLOC.)
14254951Sheideman 	 */
14354951Sheideman 	if (othervp = null_node_find(lowervp)) {
14454951Sheideman 		FREE(xp, M_TEMP);
14554951Sheideman 		vp->v_type = VBAD;	/* node is discarded */
14654951Sheideman 		vp->v_usecount = 0;	/* XXX */
14754951Sheideman 		*vpp = othervp;
14854951Sheideman 		return 0;
14954951Sheideman 	};
15054951Sheideman 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
15154951Sheideman 	hd = null_node_hash(lowervp);
15254951Sheideman 	insque(xp, hd);
15354951Sheideman 	return 0;
15454951Sheideman }
15554951Sheideman 
15654951Sheideman 
15754951Sheideman /*
15854766Sjohnh  * Try to find an existing null_node vnode refering
15954766Sjohnh  * to it, otherwise make a new null_node vnode which
16054938Sheideman  * contains a reference to the lower vnode.
16154766Sjohnh  */
16254766Sjohnh int
16354938Sheideman null_node_create(mp, lowervp, newvpp)
16454751Sjohnh 	struct mount *mp;
16554938Sheideman 	struct vnode *lowervp;
16654751Sjohnh 	struct vnode **newvpp;
16754751Sjohnh {
16854751Sjohnh 	struct vnode *aliasvp;
16954751Sjohnh 
17054938Sheideman 	if (aliasvp = null_node_find(mp, lowervp)) {
17154751Sjohnh 		/*
17254938Sheideman 		 * null_node_find has taken another reference
17354938Sheideman 		 * to the alias vnode.
17454751Sjohnh 		 */
17554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
17654938Sheideman 		vprint("null_node_create: exists", NULLTOV(ap));
17754751Sjohnh #endif
17854938Sheideman 		/* VREF(aliasvp); --- done in null_node_find */
17954751Sjohnh 	} else {
18054751Sjohnh 		int error;
18154751Sjohnh 
18254751Sjohnh 		/*
18354751Sjohnh 		 * Get new vnode.
18454751Sjohnh 		 */
18554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
18654938Sheideman 		printf("null_node_create: create new alias vnode\n");
18754751Sjohnh #endif
18854751Sjohnh 
18954751Sjohnh 		/*
19054754Sjohnh 		 * Make new vnode reference the null_node.
19154751Sjohnh 		 */
19254951Sheideman 		if (error = null_node_alloc(mp, lowervp, &aliasvp))
19354951Sheideman 			return error;
19454751Sjohnh 
19554751Sjohnh 		/*
19654751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
19754751Sjohnh 		 */
19854751Sjohnh 	}
19954751Sjohnh 
20054938Sheideman 	vrele(lowervp);
20154751Sjohnh 
20254951Sheideman #ifdef DIAGNOSTIC
20354938Sheideman 	if (lowervp->v_usecount < 1) {
20454951Sheideman 		/* Should never happen... */
20554938Sheideman 		vprint ("null_node_create: alias ");
20654938Sheideman 		vprint ("null_node_create: lower ");
20754938Sheideman 		printf ("null_node_create: lower has 0 usecount.\n");
20854938Sheideman 		panic ("null_node_create: lower has 0 usecount.");
20954938Sheideman 	};
21054951Sheideman #endif
21154938Sheideman 
21254754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21354938Sheideman 	vprint("null_node_create: alias", aliasvp);
21454938Sheideman 	vprint("null_node_create: lower", lowervp);
21554751Sjohnh #endif
21654751Sjohnh 
21754751Sjohnh 	*newvpp = aliasvp;
21854751Sjohnh 	return (0);
21954751Sjohnh }
22054754Sjohnh #ifdef NULLFS_DIAGNOSTIC
22154751Sjohnh struct vnode *
22254754Sjohnh null_checkvp(vp, fil, lno)
22354751Sjohnh 	struct vnode *vp;
22454751Sjohnh 	char *fil;
22554751Sjohnh 	int lno;
22654751Sjohnh {
22754938Sheideman 	struct null_node *a = VTONULL(vp);
22855025Smckusick #ifdef notyet
22954938Sheideman 	/*
23054938Sheideman 	 * Can't do this check because vop_reclaim runs
23154938Sheideman 	 * with a funny vop vector.
23254938Sheideman 	 */
23354938Sheideman 	if (vp->v_op != null_vnodeop_p) {
23454938Sheideman 		printf ("null_checkvp: on non-null-node\n");
23554938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
23654938Sheideman 		panic("null_checkvp");
23754938Sheideman 	};
23854938Sheideman #endif
23954938Sheideman 	if (a->null_lowervp == NULL) {
24054766Sjohnh 		/* Should never happen */
24154751Sjohnh 		int i; u_long *p;
24254751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
24354751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
24454751Sjohnh 			printf(" %x", p[i]);
24554751Sjohnh 		printf("\n");
24654938Sheideman 		/* wait for debugger */
24754938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
24854754Sjohnh 		panic("null_checkvp");
24954751Sjohnh 	}
25054938Sheideman 	if (a->null_lowervp->v_usecount < 1) {
25154938Sheideman 		int i; u_long *p;
25254938Sheideman 		printf("vp = %x, unref'ed lowervp\n", vp);
25354938Sheideman 		for (p = (u_long *) a, i = 0; i < 8; i++)
25454938Sheideman 			printf(" %x", p[i]);
25554938Sheideman 		printf("\n");
25654938Sheideman 		/* wait for debugger */
25754938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
25854938Sheideman 		panic ("null with unref'ed lowervp");
25954938Sheideman 	};
26055025Smckusick #ifdef notyet
26154938Sheideman 	printf("null %x/%d -> %x/%d [%s, %d]\n",
26254938Sheideman 	        NULLTOV(a), NULLTOV(a)->v_usecount,
26354766Sjohnh 		a->null_lowervp, a->null_lowervp->v_usecount,
26454751Sjohnh 		fil, lno);
26554938Sheideman #endif
26654754Sjohnh 	return a->null_lowervp;
26754751Sjohnh }
26854751Sjohnh #endif
269