xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 54951)
154751Sjohnh /*
254751Sjohnh  * Copyright (c) 1992 The Regents of the University of California
354751Sjohnh  * Copyright (c) 1990, 1992 Jan-Simon Pendry
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  *
1154751Sjohnh  *	@(#)lofs_subr.c	1.2 (Berkeley) 6/18/92
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>
2454893Sheideman #include <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 {
69*54951Sheideman 
7054938Sheideman 	return (&null_node_cache[NULL_NHASH(lowervp)]);
7154751Sjohnh }
7254751Sjohnh 
7354751Sjohnh 
7454766Sjohnh /*
7554938Sheideman  * XXX - this should go elsewhere.
7654938Sheideman  * Just like vget, but with no lock at the end.
7754751Sjohnh  */
7854938Sheideman int
7954938Sheideman vget_nolock(vp)
8054938Sheideman 	register struct vnode *vp;
8154938Sheideman {
8254938Sheideman 	extern struct vnode *vfreeh, **vfreet;
8354938Sheideman 	register struct vnode *vq;
8454938Sheideman 
8554938Sheideman 	if (vp->v_flag & VXLOCK) {
8654938Sheideman 		vp->v_flag |= VXWANT;
8754938Sheideman 		sleep((caddr_t)vp, PINOD);
8854938Sheideman 		return (1);
8954938Sheideman 	}
9054938Sheideman 	if (vp->v_usecount == 0) {
9154938Sheideman 		if (vq = vp->v_freef)
9254938Sheideman 			vq->v_freeb = vp->v_freeb;
9354938Sheideman 		else
9454938Sheideman 			vfreet = vp->v_freeb;
9554938Sheideman 		*vp->v_freeb = vq;
9654938Sheideman 		vp->v_freef = NULL;
9754938Sheideman 		vp->v_freeb = NULL;
9854938Sheideman 	}
9954938Sheideman 	VREF(vp);
10054938Sheideman 	/* VOP_LOCK(vp); */
10154938Sheideman 	return (0);
10254938Sheideman }
10354938Sheideman 
10454938Sheideman 
10554938Sheideman /*
10654938Sheideman  * Return a VREF'ed alias for lower vnode if already exists, else 0.
10754938Sheideman  */
10854938Sheideman static struct vnode *
10954938Sheideman null_node_find(mp, lowervp)
11054751Sjohnh 	struct mount *mp;
11154938Sheideman 	struct vnode *lowervp;
11254751Sjohnh {
11354754Sjohnh 	struct null_node_cache *hd;
11454754Sjohnh 	struct null_node *a;
11554938Sheideman 	struct vnode *vp;
11654751Sjohnh 
11754751Sjohnh 	/*
11854751Sjohnh 	 * Find hash base, and then search the (two-way) linked
11954754Sjohnh 	 * list looking for a null_node structure which is referencing
12054938Sheideman 	 * the lower vnode.  If found, the increment the null_node
12154938Sheideman 	 * reference count (but NOT the lower vnode's VREF counter).
12254751Sjohnh 	 */
12354938Sheideman 	hd = null_node_hash(lowervp);
12454938Sheideman loop:
12554754Sjohnh 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
12654938Sheideman 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
12754938Sheideman 			vp = NULLTOV(a);
12854938Sheideman 			/*
129*54951Sheideman 			 * We need vget for the VXLOCK
130*54951Sheideman 			 * stuff, but we don't want to lock
131*54951Sheideman 			 * the lower node.
13254938Sheideman 			 */
13354938Sheideman 			if (vget_nolock(vp)) {
13454938Sheideman 				printf ("null_node_find: vget failed.\n");
13554938Sheideman 				goto loop;
13654938Sheideman 			};
13754938Sheideman 			return (vp);
13854751Sjohnh 		}
13954751Sjohnh 	}
14054751Sjohnh 
14154938Sheideman 	return NULL;
14254751Sjohnh }
14354751Sjohnh 
14454938Sheideman 
14554766Sjohnh /*
146*54951Sheideman  * Make a new null_node node.
147*54951Sheideman  * Vp is the alias vnode, lofsvp is the lower vnode.
148*54951Sheideman  * Maintain a reference to (lowervp).
149*54951Sheideman  */
150*54951Sheideman static int
151*54951Sheideman null_node_alloc(mp, lowervp, vpp)
152*54951Sheideman 	struct mount *mp;
153*54951Sheideman 	struct vnode *lowervp;
154*54951Sheideman 	struct vnode **vpp;
155*54951Sheideman {
156*54951Sheideman 	struct null_node_cache *hd;
157*54951Sheideman 	struct null_node *xp;
158*54951Sheideman 	struct vnode *othervp, *vp;
159*54951Sheideman 	int error;
160*54951Sheideman 
161*54951Sheideman 	if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, vpp))
162*54951Sheideman 		return (error);	/* XXX: VT_NULL above */
163*54951Sheideman 	vp = *vpp;
164*54951Sheideman 
165*54951Sheideman 	MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
166*54951Sheideman 	vp->v_type = lowervp->v_type;
167*54951Sheideman 	xp->null_vnode = vp;
168*54951Sheideman 	vp->v_data = xp;
169*54951Sheideman 	xp->null_lowervp = lowervp;
170*54951Sheideman 	/*
171*54951Sheideman 	 * Before we insert our new node onto the hash chains,
172*54951Sheideman 	 * check to see if someone else has beaten us to it.
173*54951Sheideman 	 * (We could have slept in MALLOC.)
174*54951Sheideman 	 */
175*54951Sheideman 	if (othervp = null_node_find(lowervp)) {
176*54951Sheideman 		FREE(xp, M_TEMP);
177*54951Sheideman 		vp->v_type = VBAD;	/* node is discarded */
178*54951Sheideman 		vp->v_usecount = 0;	/* XXX */
179*54951Sheideman 		*vpp = othervp;
180*54951Sheideman 		return 0;
181*54951Sheideman 	};
182*54951Sheideman 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
183*54951Sheideman 	hd = null_node_hash(lowervp);
184*54951Sheideman 	insque(xp, hd);
185*54951Sheideman 	return 0;
186*54951Sheideman }
187*54951Sheideman 
188*54951Sheideman 
189*54951Sheideman /*
19054766Sjohnh  * Try to find an existing null_node vnode refering
19154766Sjohnh  * to it, otherwise make a new null_node vnode which
19254938Sheideman  * contains a reference to the lower vnode.
19354766Sjohnh  */
19454766Sjohnh int
19554938Sheideman null_node_create(mp, lowervp, newvpp)
19654751Sjohnh 	struct mount *mp;
19754938Sheideman 	struct vnode *lowervp;
19854751Sjohnh 	struct vnode **newvpp;
19954751Sjohnh {
20054751Sjohnh 	struct vnode *aliasvp;
20154751Sjohnh 
20254938Sheideman 	if (aliasvp = null_node_find(mp, lowervp)) {
20354751Sjohnh 		/*
20454938Sheideman 		 * null_node_find has taken another reference
20554938Sheideman 		 * to the alias vnode.
20654751Sjohnh 		 */
20754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
20854938Sheideman 		vprint("null_node_create: exists", NULLTOV(ap));
20954751Sjohnh #endif
21054938Sheideman 		/* VREF(aliasvp); --- done in null_node_find */
21154751Sjohnh 	} else {
21254751Sjohnh 		int error;
21354751Sjohnh 
21454751Sjohnh 		/*
21554751Sjohnh 		 * Get new vnode.
21654751Sjohnh 		 */
21754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21854938Sheideman 		printf("null_node_create: create new alias vnode\n");
21954751Sjohnh #endif
22054751Sjohnh 
22154751Sjohnh 		/*
22254754Sjohnh 		 * Make new vnode reference the null_node.
22354751Sjohnh 		 */
224*54951Sheideman 		if (error = null_node_alloc(mp, lowervp, &aliasvp))
225*54951Sheideman 			return error;
22654751Sjohnh 
22754751Sjohnh 		/*
22854751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
22954751Sjohnh 		 */
23054751Sjohnh 	}
23154751Sjohnh 
23254938Sheideman 	vrele(lowervp);
23354751Sjohnh 
234*54951Sheideman #ifdef DIAGNOSTIC
23554938Sheideman 	if (lowervp->v_usecount < 1) {
236*54951Sheideman 		/* Should never happen... */
23754938Sheideman 		vprint ("null_node_create: alias ");
23854938Sheideman 		vprint ("null_node_create: lower ");
23954938Sheideman 		printf ("null_node_create: lower has 0 usecount.\n");
24054938Sheideman 		panic ("null_node_create: lower has 0 usecount.");
24154938Sheideman 	};
242*54951Sheideman #endif
24354938Sheideman 
24454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
24554938Sheideman 	vprint("null_node_create: alias", aliasvp);
24654938Sheideman 	vprint("null_node_create: lower", lowervp);
24754751Sjohnh #endif
24854751Sjohnh 
24954751Sjohnh 	*newvpp = aliasvp;
25054751Sjohnh 	return (0);
25154751Sjohnh }
25254754Sjohnh #ifdef NULLFS_DIAGNOSTIC
25354751Sjohnh struct vnode *
25454754Sjohnh null_checkvp(vp, fil, lno)
25554751Sjohnh 	struct vnode *vp;
25654751Sjohnh 	char *fil;
25754751Sjohnh 	int lno;
25854751Sjohnh {
25954938Sheideman 	struct null_node *a = VTONULL(vp);
26054938Sheideman #if 0
26154938Sheideman 	/*
26254938Sheideman 	 * Can't do this check because vop_reclaim runs
26354938Sheideman 	 * with a funny vop vector.
26454938Sheideman 	 */
26554938Sheideman 	if (vp->v_op != null_vnodeop_p) {
26654938Sheideman 		printf ("null_checkvp: on non-null-node\n");
26754938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
26854938Sheideman 		panic("null_checkvp");
26954938Sheideman 	};
27054938Sheideman #endif
27154938Sheideman 	if (a->null_lowervp == NULL) {
27254766Sjohnh 		/* Should never happen */
27354751Sjohnh 		int i; u_long *p;
27454751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
27554751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
27654751Sjohnh 			printf(" %x", p[i]);
27754751Sjohnh 		printf("\n");
27854938Sheideman 		/* wait for debugger */
27954938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
28054754Sjohnh 		panic("null_checkvp");
28154751Sjohnh 	}
28254938Sheideman 	if (a->null_lowervp->v_usecount < 1) {
28354938Sheideman 		int i; u_long *p;
28454938Sheideman 		printf("vp = %x, unref'ed lowervp\n", vp);
28554938Sheideman 		for (p = (u_long *) a, i = 0; i < 8; i++)
28654938Sheideman 			printf(" %x", p[i]);
28754938Sheideman 		printf("\n");
28854938Sheideman 		/* wait for debugger */
28954938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
29054938Sheideman 		panic ("null with unref'ed lowervp");
29154938Sheideman 	};
29254938Sheideman #if 0
29354938Sheideman 	printf("null %x/%d -> %x/%d [%s, %d]\n",
29454938Sheideman 	        NULLTOV(a), NULLTOV(a)->v_usecount,
29554766Sjohnh 		a->null_lowervp, a->null_lowervp->v_usecount,
29654751Sjohnh 		fil, lno);
29754938Sheideman #endif
29854754Sjohnh 	return a->null_lowervp;
29954751Sjohnh }
30054751Sjohnh #endif
301*54951Sheideman 
302*54951Sheideman 
303