xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 54754)
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>
2454751Sjohnh #include <lofs/lofs.h>
2554751Sjohnh 
2654751Sjohnh #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
27*54754Sjohnh #define	NNULLNODECACHE 16
28*54754Sjohnh #define	NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1))
2954751Sjohnh 
3054751Sjohnh /*
31*54754Sjohnh  * Null layer cache:
3254751Sjohnh  * Each cache entry holds a reference to the target vnode
3354751Sjohnh  * along with a pointer to the alias vnode.  When an
3454751Sjohnh  * entry is added the target vnode is VREF'd.  When the
3554751Sjohnh  * alias is removed the target vnode is vrele'd.
3654751Sjohnh  */
3754751Sjohnh 
3854751Sjohnh /*
3954751Sjohnh  * Cache head
4054751Sjohnh  */
41*54754Sjohnh struct null_node_cache {
42*54754Sjohnh 	struct null_node	*ac_forw;
43*54754Sjohnh 	struct null_node	*ac_back;
4454751Sjohnh };
4554751Sjohnh 
46*54754Sjohnh static struct null_node_cache null_node_cache[NNULLNODECACHE];
4754751Sjohnh 
4854751Sjohnh /*
4954751Sjohnh  * Initialise cache headers
5054751Sjohnh  */
51*54754Sjohnh nullfs_init()
5254751Sjohnh {
53*54754Sjohnh 	struct null_node_cache *ac;
54*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
55*54754Sjohnh 	printf("nullfs_init\n");		/* printed during system boot */
5654751Sjohnh #endif
5754751Sjohnh 
58*54754Sjohnh 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++)
59*54754Sjohnh 		ac->ac_forw = ac->ac_back = (struct null_node *) ac;
6054751Sjohnh }
6154751Sjohnh 
6254751Sjohnh /*
6354751Sjohnh  * Compute hash list for given target vnode
6454751Sjohnh  */
65*54754Sjohnh static struct null_node_cache *
66*54754Sjohnh null_node_hash(targetvp)
6754751Sjohnh struct vnode *targetvp;
6854751Sjohnh {
69*54754Sjohnh 	return (&null_node_cache[NULL_NHASH(targetvp)]);
7054751Sjohnh }
7154751Sjohnh 
7254751Sjohnh /*
73*54754Sjohnh  * Make a new null_node node.
7454751Sjohnh  * Vp is the alias vnode, lofsvp is the target vnode.
7554751Sjohnh  * Maintain a reference to (targetvp).
7654751Sjohnh  */
7754751Sjohnh static void
78*54754Sjohnh null_node_alloc(vp, targetvp)
7954751Sjohnh 	struct vnode *vp;
8054751Sjohnh 	struct vnode *targetvp;
8154751Sjohnh {
82*54754Sjohnh 	struct null_node_cache *hd;
83*54754Sjohnh 	struct null_node *a;
8454751Sjohnh 
85*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
86*54754Sjohnh 	printf("null_node_alloc(%x, %x)\n", vp, targetvp);
8754751Sjohnh #endif
8854751Sjohnh 
89*54754Sjohnh 	MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
90*54754Sjohnh 	a->null_vnode = vp;
9154751Sjohnh 	vp->v_data = a;
9254751Sjohnh 	VREF(targetvp);
93*54754Sjohnh 	a->null_lowervp = targetvp;
94*54754Sjohnh 	hd = null_node_hash(targetvp);
9554751Sjohnh 	insque(a, hd);
9654751Sjohnh 
97*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
9854751Sjohnh 	vprint("alloc vp", vp);
9954751Sjohnh 	vprint("alloc targetvp", targetvp);
10054751Sjohnh #endif
10154751Sjohnh }
10254751Sjohnh 
103*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
10454751Sjohnh void
105*54754Sjohnh null_node_flushmp (mp)
10654751Sjohnh 	struct mount *mp;
10754751Sjohnh {
108*54754Sjohnh 	struct null_node_cache *ac;
10954751Sjohnh 	int i = 0;
110*54754Sjohnh 	struct null_node *roota;
11154751Sjohnh 
112*54754Sjohnh 	printf("null_node_flushmp (%x)\n", mp);
11354751Sjohnh 
114*54754Sjohnh 	roota = VTONULLNODE(MOUNTTONULLMOUNT(mp)->nullm_rootvp);
11554751Sjohnh 
116*54754Sjohnh 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) {
117*54754Sjohnh 		struct null_node *a = ac->ac_forw;
118*54754Sjohnh 		while (a != (struct null_node *) ac) {
119*54754Sjohnh 			if (a != roota && a->null_vnode->v_mount == mp) {
120*54754Sjohnh 				struct vnode *vp = a->null_lowervp;
12154751Sjohnh 				if (vp) {
122*54754Sjohnh 					a->null_lowervp = 0;
12354751Sjohnh 					vprint("would vrele", vp);
12454751Sjohnh 					/*vrele(vp);*/
12554751Sjohnh 					i++;
12654751Sjohnh 				}
12754751Sjohnh 			}
128*54754Sjohnh 			a = a->null_forw;
12954751Sjohnh 		}
13054751Sjohnh 	}
13154751Sjohnh 	if (i > 0)
132*54754Sjohnh 		printf("null_node: vrele'd %d aliases\n", i);
13354751Sjohnh }
13454751Sjohnh #endif
13554751Sjohnh 
13654751Sjohnh /*
13754751Sjohnh  * Return alias for target vnode if already exists, else 0.
13854751Sjohnh  */
139*54754Sjohnh static struct null_node *
140*54754Sjohnh null_node_find(mp, targetvp)
14154751Sjohnh 	struct mount *mp;
14254751Sjohnh 	struct vnode *targetvp;
14354751Sjohnh {
144*54754Sjohnh 	struct null_node_cache *hd;
145*54754Sjohnh 	struct null_node *a;
14654751Sjohnh 
147*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
148*54754Sjohnh 	printf("null_node_find(mp = %x, target = %x)\n", mp, targetvp);
14954751Sjohnh #endif
15054751Sjohnh 
15154751Sjohnh 	/*
15254751Sjohnh 	 * Find hash base, and then search the (two-way) linked
153*54754Sjohnh 	 * list looking for a null_node structure which is referencing
154*54754Sjohnh 	 * the target vnode.  If found, the increment the null_node
15554751Sjohnh 	 * reference count (but NOT the target vnode's VREF counter).
15654751Sjohnh 	 */
157*54754Sjohnh 	hd = null_node_hash(targetvp);
15854751Sjohnh 
159*54754Sjohnh 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
160*54754Sjohnh 		if (a->null_lowervp == targetvp && a->null_vnode->v_mount == mp) {
161*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
162*54754Sjohnh 			printf("null_node_find(%x): found (%x,%x)->%x\n",
163*54754Sjohnh 				targetvp, mp, a->null_vnode, targetvp);
16454751Sjohnh #endif
16554751Sjohnh 			return (a);
16654751Sjohnh 		}
16754751Sjohnh 	}
16854751Sjohnh 
169*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
170*54754Sjohnh 	printf("null_node_find(%x, %x): NOT found\n", mp, targetvp);
17154751Sjohnh #endif
17254751Sjohnh 
17354751Sjohnh 	return (0);
17454751Sjohnh }
17554751Sjohnh 
17654751Sjohnh static int
177*54754Sjohnh null_node_alias(mp, targetvp, newvpp)
17854751Sjohnh 	struct mount *mp;
17954751Sjohnh 	struct vnode *targetvp;
18054751Sjohnh 	struct vnode **newvpp;
18154751Sjohnh {
182*54754Sjohnh 	struct null_node *ap;
18354751Sjohnh 	struct vnode *aliasvp;
18454751Sjohnh 
185*54754Sjohnh 	if (targetvp->v_type != VDIR || targetvp->v_op == null_vnodeop_p) {
18654751Sjohnh 		*newvpp = targetvp;
18754751Sjohnh 		return;
18854751Sjohnh 	}
18954751Sjohnh 
190*54754Sjohnh 	ap = null_node_find(mp, targetvp);
19154751Sjohnh 
19254751Sjohnh 	if (ap) {
19354751Sjohnh 		/*
19454751Sjohnh 		 * Take another reference to the alias vnode
19554751Sjohnh 		 */
196*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
197*54754Sjohnh 		vprint("null_node_alias: exists", ap->null_vnode);
19854751Sjohnh #endif
199*54754Sjohnh 		aliasvp = ap->null_vnode;
20054751Sjohnh 		VREF(aliasvp);
20154751Sjohnh 	} else {
20254751Sjohnh 		int error;
20354751Sjohnh 
20454751Sjohnh 		/*
20554751Sjohnh 		 * Get new vnode.
20654751Sjohnh 		 */
207*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
208*54754Sjohnh 		printf("null_node_alias: create new alias vnode\n");
20954751Sjohnh #endif
210*54754Sjohnh 		if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp))
21154751Sjohnh 			return (error);	/* XXX: VT_LOFS above */
21254751Sjohnh 
21354751Sjohnh 		/*
21454751Sjohnh 		 * Must be a directory
21554751Sjohnh 		 */
21654751Sjohnh 		aliasvp->v_type = VDIR;
21754751Sjohnh 
21854751Sjohnh 		/*
219*54754Sjohnh 		 * Make new vnode reference the null_node.
22054751Sjohnh 		 */
221*54754Sjohnh 		null_node_alloc(aliasvp, targetvp);
22254751Sjohnh 
22354751Sjohnh 		/*
22454751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
22554751Sjohnh 		 */
22654751Sjohnh 	}
22754751Sjohnh 
22854751Sjohnh 	vrele(targetvp);
22954751Sjohnh 
230*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
231*54754Sjohnh 	vprint("null_node_alias alias", aliasvp);
232*54754Sjohnh 	vprint("null_node_alias target", targetvp);
23354751Sjohnh #endif
23454751Sjohnh 
23554751Sjohnh 	*newvpp = aliasvp;
23654751Sjohnh 	return (0);
23754751Sjohnh }
23854751Sjohnh 
23954751Sjohnh /*
240*54754Sjohnh  * Try to find an existing null_node vnode refering
241*54754Sjohnh  * to it, otherwise make a new null_node vnode which
24254751Sjohnh  * contains a reference to the target vnode.
24354751Sjohnh  */
244*54754Sjohnh make_null_node(mp, vpp)
24554751Sjohnh 	struct mount *mp;
24654751Sjohnh 	struct vnode **vpp;
24754751Sjohnh {
24854751Sjohnh 	int error;
24954751Sjohnh 	struct vnode *aliasvp;
25054751Sjohnh 	struct vnode *targetvp;
25154751Sjohnh 
252*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
253*54754Sjohnh 	printf("make_null_node(mp = %x, vp = %x\n", mp, *vpp);
25454751Sjohnh #endif
25554751Sjohnh 
25654751Sjohnh 	/*
25754751Sjohnh 	 * (targetvp) is locked at this point.
25854751Sjohnh 	 */
25954751Sjohnh 	targetvp = *vpp;
26054751Sjohnh 
261*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
26254751Sjohnh 	if (targetvp == 0)
263*54754Sjohnh 		panic("make_null_node: null vp");
26454751Sjohnh #endif
26554751Sjohnh 
26654751Sjohnh 	/*
26754751Sjohnh 	 * Try to find an existing reference to the target vnodes.
26854751Sjohnh 	 */
269*54754Sjohnh 	return (null_node_alias(mp, targetvp, vpp));
27054751Sjohnh }
27154751Sjohnh 
272*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
27354751Sjohnh struct vnode *
274*54754Sjohnh null_checkvp(vp, fil, lno)
27554751Sjohnh 	struct vnode *vp;
27654751Sjohnh 	char *fil;
27754751Sjohnh 	int lno;
27854751Sjohnh {
279*54754Sjohnh 	struct null_node *a = VTONULLNODE(vp);
280*54754Sjohnh 	if (a->null_lowervp == 0) {
28154751Sjohnh 		int i; u_long *p;
28254751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
28354751Sjohnh #ifdef notdef
28454751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
28554751Sjohnh 			printf(" %x", p[i]);
28654751Sjohnh 		printf("\n");
28754751Sjohnh 		DELAY(2000000);
288*54754Sjohnh 		panic("null_checkvp");
28954751Sjohnh #endif
29054751Sjohnh 	}
29154751Sjohnh 	printf("aliasvp %x/%d -> %x/%d [%s, %d]\n",
292*54754Sjohnh 		a->null_vnode, a->null_vnode->v_usecount,
293*54754Sjohnh 		a->null_lowervp, a->null_lowervp ? a->null_lowervp->v_usecount : -42,
29454751Sjohnh 		fil, lno);
295*54754Sjohnh 	return a->null_lowervp;
29654751Sjohnh }
29754751Sjohnh #endif
298