153841Spendry /*
253841Spendry  * Copyright (c) 1992 The Regents of the University of California
353841Spendry  * Copyright (c) 1990, 1992 Jan-Simon Pendry
453841Spendry  * All rights reserved.
553841Spendry  *
653841Spendry  * This code is derived from software donated to Berkeley by
753841Spendry  * Jan-Simon Pendry.
853841Spendry  *
953841Spendry  * %sccs.include.redist.c%
1053841Spendry  *
11*54050Spendry  *	@(#)lofs_subr.c	1.2 (Berkeley) 06/18/92
1253841Spendry  *
1353841Spendry  * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
1453841Spendry  */
1553841Spendry 
1653841Spendry #include <sys/param.h>
1753841Spendry #include <sys/systm.h>
1853841Spendry #include <sys/time.h>
1953841Spendry #include <sys/types.h>
2053841Spendry #include <sys/vnode.h>
2153841Spendry #include <sys/mount.h>
2253841Spendry #include <sys/namei.h>
2353841Spendry #include <sys/malloc.h>
2453841Spendry #include <lofs/lofs.h>
2553841Spendry 
2653841Spendry #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
2753841Spendry #define	NLOFSCACHE 16
2853841Spendry #define	LOFS_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NLOFSCACHE-1))
2953841Spendry 
3053841Spendry /*
3153841Spendry  * Loopback cache:
3253841Spendry  * Each cache entry holds a reference to the target vnode
3353841Spendry  * along with a pointer to the alias vnode.  When an
3453841Spendry  * entry is added the target vnode is VREF'd.  When the
3553841Spendry  * alias is removed the target vnode is vrele'd.
3653841Spendry  */
3753841Spendry 
3853841Spendry /*
3953841Spendry  * Cache head
4053841Spendry  */
4153841Spendry struct lofscache {
4253841Spendry 	struct lofsnode	*ac_forw;
4353841Spendry 	struct lofsnode	*ac_back;
4453841Spendry };
4553841Spendry 
4653841Spendry static struct lofscache lofscache[NLOFSCACHE];
4753841Spendry 
4853841Spendry /*
4953841Spendry  * Initialise cache headers
5053841Spendry  */
5153841Spendry lofs_init()
5253841Spendry {
5353841Spendry 	struct lofscache *ac;
5453841Spendry #ifdef LOFS_DIAGNOSTIC
5553841Spendry 	printf("lofs_init\n");		/* printed during system boot */
5653841Spendry #endif
5753841Spendry 
5853841Spendry 	for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++)
5953841Spendry 		ac->ac_forw = ac->ac_back = (struct lofsnode *) ac;
6053841Spendry }
6153841Spendry 
6253841Spendry /*
6353841Spendry  * Compute hash list for given target vnode
6453841Spendry  */
6553841Spendry static struct lofscache *
6653841Spendry lofs_hash(targetvp)
6753841Spendry struct vnode *targetvp;
6853841Spendry {
6953841Spendry 	return (&lofscache[LOFS_NHASH(targetvp)]);
7053841Spendry }
7153841Spendry 
7253841Spendry /*
7353841Spendry  * Make a new lofsnode node.
7453841Spendry  * Vp is the alias vnode, lofsvp is the target vnode.
7553841Spendry  * Maintain a reference to (targetvp).
7653841Spendry  */
7753841Spendry static void
7853841Spendry lofs_alloc(vp, targetvp)
7953841Spendry 	struct vnode *vp;
8053841Spendry 	struct vnode *targetvp;
8153841Spendry {
8253841Spendry 	struct lofscache *hd;
8353841Spendry 	struct lofsnode *a;
8453841Spendry 
8553841Spendry #ifdef LOFS_DIAGNOSTIC
8653841Spendry 	printf("lofs_alloc(%x, %x)\n", vp, targetvp);
8753841Spendry #endif
8853841Spendry 
89*54050Spendry 	MALLOC(a, struct lofsnode *, sizeof(struct lofsnode), M_TEMP, M_WAITOK);
9053841Spendry 	a->a_vnode = vp;
91*54050Spendry 	vp->v_data = a;
9253841Spendry 	VREF(targetvp);
93*54050Spendry 	a->a_lofsvp = targetvp;
9453841Spendry 	hd = lofs_hash(targetvp);
9553841Spendry 	insque(a, hd);
9653841Spendry 
9753841Spendry #ifdef LOFS_DIAGNOSTIC
9853841Spendry 	vprint("alloc vp", vp);
9953841Spendry 	vprint("alloc targetvp", targetvp);
10053841Spendry #endif
10153841Spendry }
10253841Spendry 
10353841Spendry #ifdef LOFS_DIAGNOSTIC
10453841Spendry void
10553841Spendry lofs_flushmp(mp)
10653841Spendry 	struct mount *mp;
10753841Spendry {
10853841Spendry 	struct lofscache *ac;
10953841Spendry 	int i = 0;
11053841Spendry 	struct lofsnode *roota;
11153841Spendry 
11253841Spendry 	printf("lofs_flushmp(%x)\n", mp);
11353841Spendry 
11453841Spendry 	roota = LOFSP(VFSTOLOFS(mp)->rootvp);
11553841Spendry 
11653841Spendry 	for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++) {
11753841Spendry 		struct lofsnode *a = ac->ac_forw;
11853841Spendry 		while (a != (struct lofsnode *) ac) {
11953841Spendry 			if (a != roota && a->a_vnode->v_mount == mp) {
12053841Spendry 				struct vnode *vp = a->a_lofsvp;
12153841Spendry 				if (vp) {
12253841Spendry 					a->a_lofsvp = 0;
12353841Spendry 					vprint("would vrele", vp);
12453841Spendry 					/*vrele(vp);*/
12553841Spendry 					i++;
12653841Spendry 				}
12753841Spendry 			}
12853841Spendry 			a = a->a_forw;
12953841Spendry 		}
13053841Spendry 	}
13153841Spendry 	if (i > 0)
13253841Spendry 		printf("lofsnode: vrele'd %d aliases\n", i);
13353841Spendry }
13453841Spendry #endif
13553841Spendry 
13653841Spendry /*
13753841Spendry  * Return alias for target vnode if already exists, else 0.
13853841Spendry  */
13953841Spendry static struct lofsnode *
14053841Spendry lofs_find(mp, targetvp)
14153841Spendry 	struct mount *mp;
14253841Spendry 	struct vnode *targetvp;
14353841Spendry {
14453841Spendry 	struct lofscache *hd;
14553841Spendry 	struct lofsnode *a;
14653841Spendry 
14753841Spendry #ifdef LOFS_DIAGNOSTIC
14853841Spendry 	printf("lofs_find(mp = %x, target = %x)\n", mp, targetvp);
14953841Spendry #endif
15053841Spendry 
15153841Spendry 	/*
15253841Spendry 	 * Find hash base, and then search the (two-way) linked
15353841Spendry 	 * list looking for a lofsnode structure which is referencing
15453841Spendry 	 * the target vnode.  If found, the increment the lofsnode
15553841Spendry 	 * reference count (but NOT the target vnode's VREF counter).
15653841Spendry 	 */
15753841Spendry 	hd = lofs_hash(targetvp);
15853841Spendry 
15953841Spendry 	for (a = hd->ac_forw; a != (struct lofsnode *) hd; a = a->a_forw) {
16053841Spendry 		if (a->a_lofsvp == targetvp && a->a_vnode->v_mount == mp) {
16153841Spendry #ifdef LOFS_DIAGNOSTIC
16253841Spendry 			printf("lofs_find(%x): found (%x,%x)->%x\n",
16353841Spendry 				targetvp, mp, a->a_vnode, targetvp);
16453841Spendry #endif
16553841Spendry 			return (a);
16653841Spendry 		}
16753841Spendry 	}
16853841Spendry 
16953841Spendry #ifdef LOFS_DIAGNOSTIC
17053841Spendry 	printf("lofs_find(%x, %x): NOT found\n", mp, targetvp);
17153841Spendry #endif
17253841Spendry 
17353841Spendry 	return (0);
17453841Spendry }
17553841Spendry 
17653841Spendry static int
17753841Spendry lofs_alias(mp, targetvp, newvpp)
17853841Spendry 	struct mount *mp;
17953841Spendry 	struct vnode *targetvp;
18053841Spendry 	struct vnode **newvpp;
18153841Spendry {
18253841Spendry 	struct lofsnode *ap;
18353841Spendry 	struct vnode *aliasvp;
18453841Spendry 
18553841Spendry 	if (targetvp->v_type != VDIR || targetvp->v_op == lofs_vnodeop_p) {
18653841Spendry 		*newvpp = targetvp;
18753841Spendry 		return;
18853841Spendry 	}
18953841Spendry 
19053841Spendry 	ap = lofs_find(mp, targetvp);
19153841Spendry 
19253841Spendry 	if (ap) {
19353841Spendry 		/*
19453841Spendry 		 * Take another reference to the alias vnode
19553841Spendry 		 */
19653841Spendry #ifdef LOFS_DIAGNOSTIC
19753841Spendry 		vprint("lofs_alias: exists", ap->a_vnode);
19853841Spendry #endif
19953841Spendry 		aliasvp = ap->a_vnode;
20053841Spendry 		VREF(aliasvp);
20153841Spendry 	} else {
20253841Spendry 		int error;
20353841Spendry 
20453841Spendry 		/*
20553841Spendry 		 * Get new vnode.
20653841Spendry 		 */
20753841Spendry #ifdef LOFS_DIAGNOSTIC
20853841Spendry 		printf("lofs_alias: create new alias vnode\n");
20953841Spendry #endif
21053841Spendry 		if (error = getnewvnode(VT_UFS, mp, lofs_vnodeop_p, &aliasvp))
21153841Spendry 			return (error);	/* XXX: VT_LOFS above */
21253841Spendry 
21353841Spendry 		/*
21453841Spendry 		 * Must be a directory
21553841Spendry 		 */
21653841Spendry 		aliasvp->v_type = VDIR;
21753841Spendry 
21853841Spendry 		/*
21953841Spendry 		 * Make new vnode reference the lofsnode.
22053841Spendry 		 */
22153841Spendry 		lofs_alloc(aliasvp, targetvp);
22253841Spendry 
22353841Spendry 		/*
22453841Spendry 		 * aliasvp is already VREF'd by getnewvnode()
22553841Spendry 		 */
22653841Spendry 	}
22753841Spendry 
22853841Spendry 	vrele(targetvp);
22953841Spendry 
23053841Spendry #ifdef LOFS_DIAGNOSTIC
23153841Spendry 	vprint("lofs_alias alias", aliasvp);
23253841Spendry 	vprint("lofs_alias target", targetvp);
23353841Spendry #endif
23453841Spendry 
23553841Spendry 	*newvpp = aliasvp;
23653841Spendry 	return (0);
23753841Spendry }
23853841Spendry 
23953841Spendry /*
24053841Spendry  * Try to find an existing lofsnode vnode refering
24153841Spendry  * to it, otherwise make a new lofsnode vnode which
24253841Spendry  * contains a reference to the target vnode.
24353841Spendry  */
24453841Spendry make_lofs(mp, vpp)
24553841Spendry 	struct mount *mp;
24653841Spendry 	struct vnode **vpp;
24753841Spendry {
24853841Spendry 	int error;
24953841Spendry 	struct vnode *aliasvp;
25053841Spendry 	struct vnode *targetvp;
25153841Spendry 
25253841Spendry #ifdef LOFS_DIAGNOSTIC
25353841Spendry 	printf("make_lofs(mp = %x, vp = %x\n", mp, *vpp);
25453841Spendry #endif
25553841Spendry 
25653841Spendry 	/*
25753841Spendry 	 * (targetvp) is locked at this point.
25853841Spendry 	 */
25953841Spendry 	targetvp = *vpp;
26053841Spendry 
26153841Spendry #ifdef LOFS_DIAGNOSTIC
26253841Spendry 	if (targetvp == 0)
26353841Spendry 		panic("make_lofs: null vp");
26453841Spendry #endif
26553841Spendry 
26653841Spendry 	/*
26753841Spendry 	 * Try to find an existing reference to the target vnodes.
26853841Spendry 	 */
26953841Spendry 	return (lofs_alias(mp, targetvp, vpp));
27053841Spendry }
27153841Spendry 
27253841Spendry #ifdef LOFS_DIAGNOSTIC
27353841Spendry struct vnode *
27453841Spendry lofs_checkvp(vp, fil, lno)
27553841Spendry 	struct vnode *vp;
27653841Spendry 	char *fil;
27753841Spendry 	int lno;
27853841Spendry {
27953841Spendry 	struct lofsnode *a = LOFSP(vp);
28053841Spendry 	if (a->a_lofsvp == 0) {
28153841Spendry 		int i; u_long *p;
28253841Spendry 		printf("vp = %x, ZERO ptr\n", vp);
28353841Spendry #ifdef notdef
28453841Spendry 		for (p = (u_long *) a, i = 0; i < 8; i++)
28553841Spendry 			printf(" %x", p[i]);
28653841Spendry 		printf("\n");
28753841Spendry 		DELAY(2000000);
28853841Spendry 		panic("lofs_checkvp");
28953841Spendry #endif
29053841Spendry 	}
29153841Spendry 	printf("aliasvp %x/%d -> %x/%d [%s, %d]\n",
29253841Spendry 		a->a_vnode, a->a_vnode->v_usecount,
29353841Spendry 		a->a_lofsvp, a->a_lofsvp ? a->a_lofsvp->v_usecount : -42,
29453841Spendry 		fil, lno);
29553841Spendry 	return a->a_lofsvp;
29653841Spendry }
29753841Spendry #endif
298