xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 54893)
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>
24*54893Sheideman #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:
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  */
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 /*
6354751Sjohnh  * Compute hash list for given target vnode
6454751Sjohnh  */
6554754Sjohnh static struct null_node_cache *
6654754Sjohnh null_node_hash(targetvp)
6754751Sjohnh struct vnode *targetvp;
6854751Sjohnh {
6954754Sjohnh 	return (&null_node_cache[NULL_NHASH(targetvp)]);
7054751Sjohnh }
7154751Sjohnh 
7254751Sjohnh /*
7354754Sjohnh  * 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
7854754Sjohnh null_node_alloc(vp, targetvp)
7954751Sjohnh 	struct vnode *vp;
8054751Sjohnh 	struct vnode *targetvp;
8154751Sjohnh {
8254754Sjohnh 	struct null_node_cache *hd;
8354754Sjohnh 	struct null_node *a;
8454751Sjohnh 
8554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
8654754Sjohnh 	printf("null_node_alloc(%x, %x)\n", vp, targetvp);
8754751Sjohnh #endif
8854751Sjohnh 
8954754Sjohnh 	MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
9054754Sjohnh 	a->null_vnode = vp;
9154751Sjohnh 	vp->v_data = a;
9254751Sjohnh 	VREF(targetvp);
9354754Sjohnh 	a->null_lowervp = targetvp;
9454754Sjohnh 	hd = null_node_hash(targetvp);
9554751Sjohnh 	insque(a, hd);
9654751Sjohnh 
9754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
9854751Sjohnh 	vprint("alloc vp", vp);
9954751Sjohnh 	vprint("alloc targetvp", targetvp);
10054751Sjohnh #endif
10154751Sjohnh }
10254751Sjohnh 
10354754Sjohnh #ifdef NULLFS_DIAGNOSTIC
10454766Sjohnh /*
10554766Sjohnh  * NEEDSWORK:  The ability to set lowervp to null here
10654766Sjohnh  * implies that one can never count on lowervp staying null
10754766Sjohnh  * (even if vp is locked).  This seems quite bad.  Think
10854766Sjohnh  * about these things.
10954766Sjohnh  */
11054751Sjohnh void
11154754Sjohnh null_node_flushmp (mp)
11254751Sjohnh 	struct mount *mp;
11354751Sjohnh {
11454754Sjohnh 	struct null_node_cache *ac;
11554751Sjohnh 	int i = 0;
11654754Sjohnh 	struct null_node *roota;
11754751Sjohnh 
11854754Sjohnh 	printf("null_node_flushmp (%x)\n", mp);
11954751Sjohnh 
12054754Sjohnh 	roota = VTONULLNODE(MOUNTTONULLMOUNT(mp)->nullm_rootvp);
12154751Sjohnh 
12254754Sjohnh 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) {
12354754Sjohnh 		struct null_node *a = ac->ac_forw;
12454754Sjohnh 		while (a != (struct null_node *) ac) {
12554754Sjohnh 			if (a != roota && a->null_vnode->v_mount == mp) {
12654754Sjohnh 				struct vnode *vp = a->null_lowervp;
12754751Sjohnh 				if (vp) {
12854754Sjohnh 					a->null_lowervp = 0;
12954751Sjohnh 					vprint("would vrele", vp);
13054751Sjohnh 					/*vrele(vp);*/
13154751Sjohnh 					i++;
13254751Sjohnh 				}
13354751Sjohnh 			}
13454754Sjohnh 			a = a->null_forw;
13554751Sjohnh 		}
13654751Sjohnh 	}
13754751Sjohnh 	if (i > 0)
13854754Sjohnh 		printf("null_node: vrele'd %d aliases\n", i);
13954751Sjohnh }
14054751Sjohnh #endif
14154751Sjohnh 
14254751Sjohnh /*
14354751Sjohnh  * Return alias for target vnode if already exists, else 0.
14454751Sjohnh  */
14554754Sjohnh static struct null_node *
14654754Sjohnh null_node_find(mp, targetvp)
14754751Sjohnh 	struct mount *mp;
14854751Sjohnh 	struct vnode *targetvp;
14954751Sjohnh {
15054754Sjohnh 	struct null_node_cache *hd;
15154754Sjohnh 	struct null_node *a;
15254751Sjohnh 
15354754Sjohnh #ifdef NULLFS_DIAGNOSTIC
15454754Sjohnh 	printf("null_node_find(mp = %x, target = %x)\n", mp, targetvp);
15554751Sjohnh #endif
15654751Sjohnh 
15754751Sjohnh 	/*
15854751Sjohnh 	 * Find hash base, and then search the (two-way) linked
15954754Sjohnh 	 * list looking for a null_node structure which is referencing
16054754Sjohnh 	 * the target vnode.  If found, the increment the null_node
16154751Sjohnh 	 * reference count (but NOT the target vnode's VREF counter).
16254751Sjohnh 	 */
16354754Sjohnh 	hd = null_node_hash(targetvp);
16454751Sjohnh 
16554754Sjohnh 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
16654754Sjohnh 		if (a->null_lowervp == targetvp && a->null_vnode->v_mount == mp) {
16754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
16854754Sjohnh 			printf("null_node_find(%x): found (%x,%x)->%x\n",
16954754Sjohnh 				targetvp, mp, a->null_vnode, targetvp);
17054751Sjohnh #endif
17154751Sjohnh 			return (a);
17254751Sjohnh 		}
17354751Sjohnh 	}
17454751Sjohnh 
17554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
17654754Sjohnh 	printf("null_node_find(%x, %x): NOT found\n", mp, targetvp);
17754751Sjohnh #endif
17854751Sjohnh 
17954751Sjohnh 	return (0);
18054751Sjohnh }
18154751Sjohnh 
18254766Sjohnh /*
18354766Sjohnh  * Try to find an existing null_node vnode refering
18454766Sjohnh  * to it, otherwise make a new null_node vnode which
18554766Sjohnh  * contains a reference to the target vnode.
18654766Sjohnh  */
18754766Sjohnh int
18854766Sjohnh null_node_create(mp, targetvp, newvpp)
18954751Sjohnh 	struct mount *mp;
19054751Sjohnh 	struct vnode *targetvp;
19154751Sjohnh 	struct vnode **newvpp;
19254751Sjohnh {
19354754Sjohnh 	struct null_node *ap;
19454751Sjohnh 	struct vnode *aliasvp;
19554751Sjohnh 
19654754Sjohnh 	if (targetvp->v_type != VDIR || targetvp->v_op == null_vnodeop_p) {
19754751Sjohnh 		*newvpp = targetvp;
19854751Sjohnh 		return;
19954751Sjohnh 	}
20054751Sjohnh 
20154754Sjohnh 	ap = null_node_find(mp, targetvp);
20254751Sjohnh 
20354751Sjohnh 	if (ap) {
20454751Sjohnh 		/*
20554751Sjohnh 		 * Take another reference to the alias vnode
20654751Sjohnh 		 */
20754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
20854754Sjohnh 		vprint("null_node_alias: exists", ap->null_vnode);
20954751Sjohnh #endif
21054754Sjohnh 		aliasvp = ap->null_vnode;
21154751Sjohnh 		VREF(aliasvp);
21254751Sjohnh 	} else {
21354751Sjohnh 		int error;
21454751Sjohnh 
21554751Sjohnh 		/*
21654751Sjohnh 		 * Get new vnode.
21754751Sjohnh 		 */
21854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21954754Sjohnh 		printf("null_node_alias: create new alias vnode\n");
22054751Sjohnh #endif
22154754Sjohnh 		if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp))
22254751Sjohnh 			return (error);	/* XXX: VT_LOFS above */
22354751Sjohnh 
22454751Sjohnh 		/*
22554751Sjohnh 		 * Must be a directory
22654751Sjohnh 		 */
22754751Sjohnh 		aliasvp->v_type = VDIR;
22854751Sjohnh 
22954751Sjohnh 		/*
23054754Sjohnh 		 * Make new vnode reference the null_node.
23154751Sjohnh 		 */
23254754Sjohnh 		null_node_alloc(aliasvp, targetvp);
23354751Sjohnh 
23454751Sjohnh 		/*
23554751Sjohnh 		 * aliasvp is already VREF'd by getnewvnode()
23654751Sjohnh 		 */
23754751Sjohnh 	}
23854751Sjohnh 
23954751Sjohnh 	vrele(targetvp);
24054751Sjohnh 
24154754Sjohnh #ifdef NULLFS_DIAGNOSTIC
24254754Sjohnh 	vprint("null_node_alias alias", aliasvp);
24354754Sjohnh 	vprint("null_node_alias target", targetvp);
24454751Sjohnh #endif
24554751Sjohnh 
24654751Sjohnh 	*newvpp = aliasvp;
24754751Sjohnh 	return (0);
24854751Sjohnh }
24954754Sjohnh #ifdef NULLFS_DIAGNOSTIC
25054751Sjohnh struct vnode *
25154754Sjohnh null_checkvp(vp, fil, lno)
25254751Sjohnh 	struct vnode *vp;
25354751Sjohnh 	char *fil;
25454751Sjohnh 	int lno;
25554751Sjohnh {
25654754Sjohnh 	struct null_node *a = VTONULLNODE(vp);
25754754Sjohnh 	if (a->null_lowervp == 0) {
25854766Sjohnh 		/* Should never happen */
25954751Sjohnh 		int i; u_long *p;
26054751Sjohnh 		printf("vp = %x, ZERO ptr\n", vp);
26154751Sjohnh 		for (p = (u_long *) a, i = 0; i < 8; i++)
26254751Sjohnh 			printf(" %x", p[i]);
26354751Sjohnh 		printf("\n");
26454751Sjohnh 		DELAY(2000000);
26554754Sjohnh 		panic("null_checkvp");
26654751Sjohnh 	}
26754766Sjohnh 	printf("nullvp %x/%d -> %x/%d [%s, %d]\n",
26854754Sjohnh 		a->null_vnode, a->null_vnode->v_usecount,
26954766Sjohnh 		a->null_lowervp, a->null_lowervp->v_usecount,
27054751Sjohnh 		fil, lno);
27154754Sjohnh 	return a->null_lowervp;
27254751Sjohnh }
27354751Sjohnh #endif
274