153841Spendry /*
263237Sbostic * Copyright (c) 1992, 1993
363237Sbostic * The Regents of the University of California. All rights reserved.
453841Spendry *
553841Spendry * This code is derived from software donated to Berkeley by
653841Spendry * Jan-Simon Pendry.
753841Spendry *
853841Spendry * %sccs.include.redist.c%
953841Spendry *
10*65803Sbostic * @(#)lofs_subr.c 8.5 (Berkeley) 01/21/94
1153841Spendry *
1253841Spendry * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
1353841Spendry */
1453841Spendry
1553841Spendry #include <sys/param.h>
1653841Spendry #include <sys/systm.h>
1753841Spendry #include <sys/time.h>
1853841Spendry #include <sys/types.h>
1953841Spendry #include <sys/vnode.h>
2053841Spendry #include <sys/mount.h>
2153841Spendry #include <sys/namei.h>
2253841Spendry #include <sys/malloc.h>
2355022Smckusick #include <miscfs/lofs/lofs.h>
2453841Spendry
2553841Spendry #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
2653841Spendry #define NLOFSCACHE 16
2753841Spendry #define LOFS_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NLOFSCACHE-1))
2853841Spendry
2953841Spendry /*
3053841Spendry * Loopback cache:
3153841Spendry * Each cache entry holds a reference to the target vnode
3253841Spendry * along with a pointer to the alias vnode. When an
3353841Spendry * entry is added the target vnode is VREF'd. When the
3453841Spendry * alias is removed the target vnode is vrele'd.
3553841Spendry */
3653841Spendry
3753841Spendry /*
3853841Spendry * Cache head
3953841Spendry */
4053841Spendry struct lofscache {
4153841Spendry struct lofsnode *ac_forw;
4253841Spendry struct lofsnode *ac_back;
4353841Spendry };
4453841Spendry
4553841Spendry static struct lofscache lofscache[NLOFSCACHE];
4653841Spendry
4753841Spendry /*
4853841Spendry * Initialise cache headers
4953841Spendry */
5065518Spendry int
lofs_init()5153841Spendry lofs_init()
5253841Spendry {
5353841Spendry struct lofscache *ac;
5453841Spendry
5553841Spendry for (ac = lofscache; ac < lofscache + NLOFSCACHE; ac++)
5653841Spendry ac->ac_forw = ac->ac_back = (struct lofsnode *) ac;
5765518Spendry
5865518Spendry return (0);
5953841Spendry }
6053841Spendry
6153841Spendry /*
6253841Spendry * Compute hash list for given target vnode
6353841Spendry */
6453841Spendry static struct lofscache *
lofs_hash(targetvp)6553841Spendry lofs_hash(targetvp)
6653841Spendry struct vnode *targetvp;
6753841Spendry {
6865518Spendry
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
lofs_alloc(vp,targetvp)7853841Spendry lofs_alloc(vp, targetvp)
7953841Spendry struct vnode *vp;
8053841Spendry struct vnode *targetvp;
8153841Spendry {
8253841Spendry struct lofscache *hd;
8353841Spendry struct lofsnode *a;
8453841Spendry
8554050Spendry MALLOC(a, struct lofsnode *, sizeof(struct lofsnode), M_TEMP, M_WAITOK);
8653841Spendry a->a_vnode = vp;
8754050Spendry vp->v_data = a;
8853841Spendry VREF(targetvp);
8954050Spendry a->a_lofsvp = targetvp;
9053841Spendry hd = lofs_hash(targetvp);
9153841Spendry insque(a, hd);
9253841Spendry
9353841Spendry }
9453841Spendry
9553841Spendry
9653841Spendry /*
9753841Spendry * Return alias for target vnode if already exists, else 0.
9853841Spendry */
9953841Spendry static struct lofsnode *
lofs_find(mp,targetvp)10053841Spendry lofs_find(mp, targetvp)
10153841Spendry struct mount *mp;
10253841Spendry struct vnode *targetvp;
10353841Spendry {
10453841Spendry struct lofscache *hd;
10553841Spendry struct lofsnode *a;
10653841Spendry
10753841Spendry /*
10853841Spendry * Find hash base, and then search the (two-way) linked
10953841Spendry * list looking for a lofsnode structure which is referencing
11053841Spendry * the target vnode. If found, the increment the lofsnode
11153841Spendry * reference count (but NOT the target vnode's VREF counter).
11253841Spendry */
11353841Spendry hd = lofs_hash(targetvp);
11453841Spendry
11553841Spendry for (a = hd->ac_forw; a != (struct lofsnode *) hd; a = a->a_forw) {
11653841Spendry if (a->a_lofsvp == targetvp && a->a_vnode->v_mount == mp) {
11753841Spendry return (a);
11853841Spendry }
11953841Spendry }
12053841Spendry
12153841Spendry return (0);
12253841Spendry }
12353841Spendry
12453841Spendry static int
lofs_alias(mp,targetvp,newvpp)12553841Spendry lofs_alias(mp, targetvp, newvpp)
12653841Spendry struct mount *mp;
12753841Spendry struct vnode *targetvp;
12853841Spendry struct vnode **newvpp;
12953841Spendry {
13053841Spendry struct lofsnode *ap;
13153841Spendry struct vnode *aliasvp;
13253841Spendry
13353841Spendry if (targetvp->v_type != VDIR || targetvp->v_op == lofs_vnodeop_p) {
13453841Spendry *newvpp = targetvp;
13559741Spendry return (0);
13653841Spendry }
13753841Spendry
13853841Spendry ap = lofs_find(mp, targetvp);
13953841Spendry
14053841Spendry if (ap) {
14153841Spendry /*
14253841Spendry * Take another reference to the alias vnode
14353841Spendry */
14453841Spendry aliasvp = ap->a_vnode;
14553841Spendry VREF(aliasvp);
14653841Spendry } else {
14753841Spendry int error;
14853841Spendry
14953841Spendry /*
15053841Spendry * Get new vnode.
15153841Spendry */
15265380Spendry if (error = getnewvnode(VT_LOFS, mp, lofs_vnodeop_p, &aliasvp))
15365380Spendry return (error);
15453841Spendry
15553841Spendry /*
15653841Spendry * Must be a directory
15753841Spendry */
15853841Spendry aliasvp->v_type = VDIR;
15953841Spendry
16053841Spendry /*
16153841Spendry * Make new vnode reference the lofsnode.
16253841Spendry */
16353841Spendry lofs_alloc(aliasvp, targetvp);
16453841Spendry
16553841Spendry /*
16653841Spendry * aliasvp is already VREF'd by getnewvnode()
16753841Spendry */
16853841Spendry }
16953841Spendry
17053841Spendry vrele(targetvp);
17153841Spendry
17253841Spendry *newvpp = aliasvp;
17353841Spendry return (0);
17453841Spendry }
17553841Spendry
17653841Spendry /*
17753841Spendry * Try to find an existing lofsnode vnode refering
17853841Spendry * to it, otherwise make a new lofsnode vnode which
17953841Spendry * contains a reference to the target vnode.
18053841Spendry */
18165518Spendry int
make_lofs(mp,vpp)18253841Spendry make_lofs(mp, vpp)
18353841Spendry struct mount *mp;
18453841Spendry struct vnode **vpp;
18553841Spendry {
18653841Spendry struct vnode *targetvp;
18753841Spendry
18853841Spendry /*
18953841Spendry * (targetvp) is locked at this point.
19053841Spendry */
19153841Spendry targetvp = *vpp;
19253841Spendry
19353841Spendry /*
19453841Spendry * Try to find an existing reference to the target vnodes.
19553841Spendry */
19653841Spendry return (lofs_alias(mp, targetvp, vpp));
19753841Spendry }
19853841Spendry
199