xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 54938)
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:
32*54938Sheideman  * Each cache entry holds a reference to the lower vnode
3354751Sjohnh  * along with a pointer to the alias vnode.  When an
34*54938Sheideman  * entry is added the lower vnode is VREF'd.  When the
35*54938Sheideman  * 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 /*
63*54938Sheideman  * Compute hash list for given lower vnode
6454751Sjohnh  */
6554754Sjohnh static struct null_node_cache *
66*54938Sheideman null_node_hash(lowervp)
67*54938Sheideman struct vnode *lowervp;
6854751Sjohnh {
69*54938Sheideman 	return (&null_node_cache[NULL_NHASH(lowervp)]);
7054751Sjohnh }
7154751Sjohnh 
7254751Sjohnh /*
7354754Sjohnh  * Make a new null_node node.
74*54938Sheideman  * Vp is the alias vnode, lofsvp is the lower vnode.
75*54938Sheideman  * Maintain a reference to (lowervp).
7654751Sjohnh  */
7754751Sjohnh static void
78*54938Sheideman null_node_alloc(vp, lowervp)
7954751Sjohnh 	struct vnode *vp;
80*54938Sheideman 	struct vnode *lowervp;
8154751Sjohnh {
8254754Sjohnh 	struct null_node_cache *hd;
8354754Sjohnh 	struct null_node *a;
8454751Sjohnh 
8554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
86*54938Sheideman 	printf("null_node_alloc(%x, %x)\n", vp, lowervp);
8754751Sjohnh #endif
8854751Sjohnh 
8954754Sjohnh 	MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
90*54938Sheideman 	vp->v_type = lowervp->v_type;
9154754Sjohnh 	a->null_vnode = vp;
9254751Sjohnh 	vp->v_data = a;
93*54938Sheideman 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
94*54938Sheideman 	a->null_lowervp = lowervp;
95*54938Sheideman 	hd = null_node_hash(lowervp);
9654751Sjohnh 	insque(a, hd);
9754751Sjohnh 
9854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
99*54938Sheideman 	vprint("null_node_alloc vp", vp);
100*54938Sheideman 	vprint("null_node_alloc lowervp", lowervp);
10154751Sjohnh #endif
10254751Sjohnh }
10354751Sjohnh 
10454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
10554766Sjohnh /*
10654766Sjohnh  * NEEDSWORK:  The ability to set lowervp to null here
10754766Sjohnh  * implies that one can never count on lowervp staying null
10854766Sjohnh  * (even if vp is locked).  This seems quite bad.  Think
10954766Sjohnh  * about these things.
11054766Sjohnh  */
11154751Sjohnh void
11254754Sjohnh null_node_flushmp (mp)
11354751Sjohnh 	struct mount *mp;
11454751Sjohnh {
11554754Sjohnh 	struct null_node_cache *ac;
11654751Sjohnh 	int i = 0;
11754754Sjohnh 	struct null_node *roota;
11854751Sjohnh 
11954754Sjohnh 	printf("null_node_flushmp (%x)\n", mp);
12054751Sjohnh 
121*54938Sheideman 	roota = VTONULL(MOUNTTONULLMOUNT(mp)->nullm_rootvp);
12254751Sjohnh 
12354754Sjohnh 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) {
12454754Sjohnh 		struct null_node *a = ac->ac_forw;
12554754Sjohnh 		while (a != (struct null_node *) ac) {
126*54938Sheideman 			if (a != roota && NULLTOV(a)->v_mount == mp) {
12754754Sjohnh 				struct vnode *vp = a->null_lowervp;
12854751Sjohnh 				if (vp) {
12954754Sjohnh 					a->null_lowervp = 0;
130*54938Sheideman 					vprint("null_flushmp: would vrele", vp);
13154751Sjohnh 					/*vrele(vp);*/
13254751Sjohnh 					i++;
13354751Sjohnh 				}
13454751Sjohnh 			}
13554754Sjohnh 			a = a->null_forw;
13654751Sjohnh 		}
13754751Sjohnh 	}
13854751Sjohnh 	if (i > 0)
13954754Sjohnh 		printf("null_node: vrele'd %d aliases\n", i);
14054751Sjohnh }
14154751Sjohnh #endif
14254751Sjohnh 
14354751Sjohnh /*
144*54938Sheideman  * XXX - this should go elsewhere.
145*54938Sheideman  * Just like vget, but with no lock at the end.
14654751Sjohnh  */
147*54938Sheideman int
148*54938Sheideman vget_nolock(vp)
149*54938Sheideman 	register struct vnode *vp;
150*54938Sheideman {
151*54938Sheideman 	extern struct vnode *vfreeh, **vfreet;
152*54938Sheideman 	register struct vnode *vq;
153*54938Sheideman 
154*54938Sheideman 	if (vp->v_flag & VXLOCK) {
155*54938Sheideman 		vp->v_flag |= VXWANT;
156*54938Sheideman 		sleep((caddr_t)vp, PINOD);
157*54938Sheideman 		return (1);
158*54938Sheideman 	}
159*54938Sheideman 	if (vp->v_usecount == 0) {
160*54938Sheideman 		if (vq = vp->v_freef)
161*54938Sheideman 			vq->v_freeb = vp->v_freeb;
162*54938Sheideman 		else
163*54938Sheideman 			vfreet = vp->v_freeb;
164*54938Sheideman 		*vp->v_freeb = vq;
165*54938Sheideman 		vp->v_freef = NULL;
166*54938Sheideman 		vp->v_freeb = NULL;
167*54938Sheideman 	}
168*54938Sheideman 	VREF(vp);
169*54938Sheideman 	/* VOP_LOCK(vp); */
170*54938Sheideman 	return (0);
171*54938Sheideman }
172*54938Sheideman 
173*54938Sheideman 
174*54938Sheideman /*
175*54938Sheideman  * Return a VREF'ed alias for lower vnode if already exists, else 0.
176*54938Sheideman  */
177*54938Sheideman static struct vnode *
178*54938Sheideman null_node_find(mp, lowervp)
17954751Sjohnh 	struct mount *mp;
180*54938Sheideman 	struct vnode *lowervp;
18154751Sjohnh {
18254754Sjohnh 	struct null_node_cache *hd;
18354754Sjohnh 	struct null_node *a;
184*54938Sheideman 	struct vnode *vp;
18554751Sjohnh 
18654754Sjohnh #ifdef NULLFS_DIAGNOSTIC
187*54938Sheideman 	printf("null_node_find(mp = %x, lower = %x)\n", mp, lowervp);
18854751Sjohnh #endif
18954751Sjohnh 
19054751Sjohnh 	/*
19154751Sjohnh 	 * Find hash base, and then search the (two-way) linked
19254754Sjohnh 	 * list looking for a null_node structure which is referencing
193*54938Sheideman 	 * the lower vnode.  If found, the increment the null_node
194*54938Sheideman 	 * reference count (but NOT the lower vnode's VREF counter).
19554751Sjohnh 	 */
196*54938Sheideman 	hd = null_node_hash(lowervp);
197*54938Sheideman loop:
19854754Sjohnh 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
199*54938Sheideman 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
20054754Sjohnh #ifdef NULLFS_DIAGNOSTIC
20154754Sjohnh 			printf("null_node_find(%x): found (%x,%x)->%x\n",
202*54938Sheideman 				lowervp, mp, NULLTOV(a), lowervp);
20354751Sjohnh #endif
204*54938Sheideman 			vp = NULLTOV(a);
205*54938Sheideman 			/*
206*54938Sheideman 			 * NEEDSWORK: Don't call the normal vget,
207*54938Sheideman 			 * it will do a VOP_LOCK which is bypassed
208*54938Sheideman 			 * and will lock against ourselves.
209*54938Sheideman 			 * Unfortunately, we need vget for the VXLOCK
210*54938Sheideman 			 * stuff.
211*54938Sheideman 			 */
212*54938Sheideman 			if (vget_nolock(vp)) {
213*54938Sheideman 				printf ("null_node_find: vget failed.\n");
214*54938Sheideman 				goto loop;
215*54938Sheideman 			};
216*54938Sheideman 			return (vp);
21754751Sjohnh 		}
21854751Sjohnh 	}
21954751Sjohnh 
22054754Sjohnh #ifdef NULLFS_DIAGNOSTIC
221*54938Sheideman 	printf("null_node_find(%x, %x): NOT found\n", mp, lowervp);
22254751Sjohnh #endif
22354751Sjohnh 
224*54938Sheideman 	return NULL;
22554751Sjohnh }
22654751Sjohnh 
227*54938Sheideman #if 1
228*54938Sheideman int null_node_create_barrier = 1;
229*54938Sheideman #endif
230*54938Sheideman 
23154766Sjohnh /*
23254766Sjohnh  * Try to find an existing null_node vnode refering
23354766Sjohnh  * to it, otherwise make a new null_node vnode which
234*54938Sheideman  * contains a reference to the lower vnode.
23554766Sjohnh  */
23654766Sjohnh int
237*54938Sheideman null_node_create(mp, lowervp, newvpp)
23854751Sjohnh 	struct mount *mp;
239*54938Sheideman 	struct vnode *lowervp;
24054751Sjohnh 	struct vnode **newvpp;
24154751Sjohnh {
24254751Sjohnh 	struct vnode *aliasvp;
24354751Sjohnh 
244*54938Sheideman 	if (aliasvp = null_node_find(mp, lowervp)) {
24554751Sjohnh 		/*
246*54938Sheideman 		 * null_node_find has taken another reference
247*54938Sheideman 		 * to the alias vnode.
24854751Sjohnh 		 */
24954754Sjohnh #ifdef NULLFS_DIAGNOSTIC
250*54938Sheideman 		vprint("null_node_create: exists", NULLTOV(ap));
25154751Sjohnh #endif
252*54938Sheideman 		/* VREF(aliasvp); --- done in null_node_find */
25354751Sjohnh 	} else {
25454751Sjohnh 		int error;
25554751Sjohnh 
25654751Sjohnh 		/*
25754751Sjohnh 		 * Get new vnode.
25854751Sjohnh 		 */
25954754Sjohnh #ifdef NULLFS_DIAGNOSTIC
260*54938Sheideman 		printf("null_node_create: create new alias vnode\n");
26154751Sjohnh #endif
26254754Sjohnh 		if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp))
263*54938Sheideman 			return (error);	/* XXX: VT_NULL above */
26454751Sjohnh 
26554751Sjohnh 		/*
26654754Sjohnh 		 * Make new vnode reference the null_node.
26754751Sjohnh 		 */
268*54938Sheideman 		null_node_alloc(aliasvp, lowervp);
26954751Sjohnh 
27054751Sjohnh 		/*
27154751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
27254751Sjohnh 		 */
27354751Sjohnh 	}
27454751Sjohnh 
275*54938Sheideman 	vrele(lowervp);
27654751Sjohnh 
277*54938Sheideman 	if (lowervp->v_usecount < 1) {
278*54938Sheideman 		vprint ("null_node_create: alias ");
279*54938Sheideman 		vprint ("null_node_create: lower ");
280*54938Sheideman 		printf ("null_node_create: lower has 0 usecount.\n");
281*54938Sheideman 		while (null_node_create_barrier) /* wait */ ;
282*54938Sheideman 		panic ("null_node_create: lower has 0 usecount.");
283*54938Sheideman 	};
284*54938Sheideman 
28554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
286*54938Sheideman 	vprint("null_node_create: alias", aliasvp);
287*54938Sheideman 	vprint("null_node_create: lower", lowervp);
28854751Sjohnh #endif
28954751Sjohnh 
29054751Sjohnh 	*newvpp = aliasvp;
29154751Sjohnh 	return (0);
29254751Sjohnh }
29354754Sjohnh #ifdef NULLFS_DIAGNOSTIC
294*54938Sheideman int null_checkvp_barrier = 1;
29554751Sjohnh struct vnode *
29654754Sjohnh null_checkvp(vp, fil, lno)
29754751Sjohnh 	struct vnode *vp;
29854751Sjohnh 	char *fil;
29954751Sjohnh 	int lno;
30054751Sjohnh {
301*54938Sheideman 	struct null_node *a = VTONULL(vp);
302*54938Sheideman #if 0
303*54938Sheideman 	/*
304*54938Sheideman 	 * Can't do this check because vop_reclaim runs
305*54938Sheideman 	 * with a funny vop vector.
306*54938Sheideman 	 */
307*54938Sheideman 	if (vp->v_op != null_vnodeop_p) {
308*54938Sheideman 		printf ("null_checkvp: on non-null-node\n");
309*54938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
310*54938Sheideman 		panic("null_checkvp");
311*54938Sheideman 	};
312*54938Sheideman #endif
313*54938Sheideman 	if (a->null_lowervp == NULL) {
31454766Sjohnh 		/* Should never happen */
31554751Sjohnh 		int i; u_long *p;
31654751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
31754751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
31854751Sjohnh 			printf(" %x", p[i]);
31954751Sjohnh 		printf("\n");
320*54938Sheideman 		/* wait for debugger */
321*54938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
32254754Sjohnh 		panic("null_checkvp");
32354751Sjohnh 	}
324*54938Sheideman 	if (a->null_lowervp->v_usecount < 1) {
325*54938Sheideman 		int i; u_long *p;
326*54938Sheideman 		printf("vp = %x, unref'ed lowervp\n", vp);
327*54938Sheideman 		for (p = (u_long *) a, i = 0; i < 8; i++)
328*54938Sheideman 			printf(" %x", p[i]);
329*54938Sheideman 		printf("\n");
330*54938Sheideman 		/* wait for debugger */
331*54938Sheideman 		while (null_checkvp_barrier) /*WAIT*/ ;
332*54938Sheideman 		panic ("null with unref'ed lowervp");
333*54938Sheideman 	};
334*54938Sheideman #if 0
335*54938Sheideman 	printf("null %x/%d -> %x/%d [%s, %d]\n",
336*54938Sheideman 	        NULLTOV(a), NULLTOV(a)->v_usecount,
33754766Sjohnh 		a->null_lowervp, a->null_lowervp->v_usecount,
33854751Sjohnh 		fil, lno);
339*54938Sheideman #endif
34054754Sjohnh 	return a->null_lowervp;
34154751Sjohnh }
34254751Sjohnh #endif
343