154751Sjohnh /*
263245Sbostic * Copyright (c) 1992, 1993
363245Sbostic * The Regents of the University of California. All rights reserved.
454751Sjohnh *
554751Sjohnh * This code is derived from software donated to Berkeley by
654751Sjohnh * Jan-Simon Pendry.
754751Sjohnh *
854751Sjohnh * %sccs.include.redist.c%
954751Sjohnh *
10*69438Smckusick * @(#)null_subr.c 8.7 (Berkeley) 05/14/95
1154751Sjohnh *
1254751Sjohnh * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
1354751Sjohnh */
1454751Sjohnh
1554751Sjohnh #include <sys/param.h>
1654751Sjohnh #include <sys/systm.h>
17*69438Smckusick #include <sys/proc.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>
2455025Smckusick #include <miscfs/nullfs/null.h>
2554751Sjohnh
2654751Sjohnh #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
2754754Sjohnh #define NNULLNODECACHE 16
2854751Sjohnh
2954751Sjohnh /*
3054754Sjohnh * Null layer cache:
3154938Sheideman * Each cache entry holds a reference to the lower vnode
3254751Sjohnh * along with a pointer to the alias vnode. When an
3354938Sheideman * entry is added the lower vnode is VREF'd. When the
3454938Sheideman * alias is removed the lower vnode is vrele'd.
3554751Sjohnh */
3654751Sjohnh
3767716Smckusick #define NULL_NHASH(vp) \
3867716Smckusick (&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash])
LIST_HEAD(null_node_hashhead,null_node)3967716Smckusick LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
4067716Smckusick u_long null_node_hash;
4154751Sjohnh
4254751Sjohnh /*
4354751Sjohnh * Initialise cache headers
4454751Sjohnh */
4554754Sjohnh nullfs_init()
4654751Sjohnh {
4767716Smckusick
4854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
4954754Sjohnh printf("nullfs_init\n"); /* printed during system boot */
5054751Sjohnh #endif
5167716Smckusick null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash);
5254751Sjohnh }
5354751Sjohnh
5454751Sjohnh /*
5554938Sheideman * Return a VREF'ed alias for lower vnode if already exists, else 0.
5654938Sheideman */
5754938Sheideman static struct vnode *
null_node_find(mp,lowervp)5854938Sheideman null_node_find(mp, lowervp)
5954751Sjohnh struct mount *mp;
6054938Sheideman struct vnode *lowervp;
6154751Sjohnh {
62*69438Smckusick struct proc *p = curproc; /* XXX */
6367716Smckusick struct null_node_hashhead *hd;
6454754Sjohnh struct null_node *a;
6554938Sheideman struct vnode *vp;
6654751Sjohnh
6754751Sjohnh /*
6854751Sjohnh * Find hash base, and then search the (two-way) linked
6954754Sjohnh * list looking for a null_node structure which is referencing
7054938Sheideman * the lower vnode. If found, the increment the null_node
7154938Sheideman * reference count (but NOT the lower vnode's VREF counter).
7254751Sjohnh */
7367716Smckusick hd = NULL_NHASH(lowervp);
7454938Sheideman loop:
7567716Smckusick for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) {
7654938Sheideman if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
7754938Sheideman vp = NULLTOV(a);
7854938Sheideman /*
7954951Sheideman * We need vget for the VXLOCK
8054951Sheideman * stuff, but we don't want to lock
8154951Sheideman * the lower node.
8254938Sheideman */
83*69438Smckusick if (vget(vp, 0, p)) {
8454938Sheideman printf ("null_node_find: vget failed.\n");
8554938Sheideman goto loop;
8654938Sheideman };
8754938Sheideman return (vp);
8854751Sjohnh }
8954751Sjohnh }
9054751Sjohnh
9154938Sheideman return NULL;
9254751Sjohnh }
9354751Sjohnh
9454938Sheideman
9554766Sjohnh /*
9654951Sheideman * Make a new null_node node.
9754951Sheideman * Vp is the alias vnode, lofsvp is the lower vnode.
9854951Sheideman * Maintain a reference to (lowervp).
9954951Sheideman */
10054951Sheideman static int
null_node_alloc(mp,lowervp,vpp)10154951Sheideman null_node_alloc(mp, lowervp, vpp)
10254951Sheideman struct mount *mp;
10354951Sheideman struct vnode *lowervp;
10454951Sheideman struct vnode **vpp;
10554951Sheideman {
10667716Smckusick struct null_node_hashhead *hd;
10754951Sheideman struct null_node *xp;
10854951Sheideman struct vnode *othervp, *vp;
10954951Sheideman int error;
11054951Sheideman
11165424Spendry if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
11265424Spendry return (error);
11354951Sheideman vp = *vpp;
11454951Sheideman
11554951Sheideman MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
11654951Sheideman vp->v_type = lowervp->v_type;
11754951Sheideman xp->null_vnode = vp;
11854951Sheideman vp->v_data = xp;
11954951Sheideman xp->null_lowervp = lowervp;
12054951Sheideman /*
12154951Sheideman * Before we insert our new node onto the hash chains,
12254951Sheideman * check to see if someone else has beaten us to it.
12354951Sheideman * (We could have slept in MALLOC.)
12454951Sheideman */
12554951Sheideman if (othervp = null_node_find(lowervp)) {
12654951Sheideman FREE(xp, M_TEMP);
12754951Sheideman vp->v_type = VBAD; /* node is discarded */
12854951Sheideman vp->v_usecount = 0; /* XXX */
12954951Sheideman *vpp = othervp;
13054951Sheideman return 0;
13154951Sheideman };
13254951Sheideman VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */
13367716Smckusick hd = NULL_NHASH(lowervp);
13467716Smckusick LIST_INSERT_HEAD(hd, xp, null_hash);
13554951Sheideman return 0;
13654951Sheideman }
13754951Sheideman
13854951Sheideman
13954951Sheideman /*
14054766Sjohnh * Try to find an existing null_node vnode refering
14154766Sjohnh * to it, otherwise make a new null_node vnode which
14254938Sheideman * contains a reference to the lower vnode.
14354766Sjohnh */
14454766Sjohnh int
null_node_create(mp,lowervp,newvpp)14554938Sheideman null_node_create(mp, lowervp, newvpp)
14654751Sjohnh struct mount *mp;
14754938Sheideman struct vnode *lowervp;
14854751Sjohnh struct vnode **newvpp;
14954751Sjohnh {
15054751Sjohnh struct vnode *aliasvp;
15154751Sjohnh
15254938Sheideman if (aliasvp = null_node_find(mp, lowervp)) {
15354751Sjohnh /*
15454938Sheideman * null_node_find has taken another reference
15554938Sheideman * to the alias vnode.
15654751Sjohnh */
15754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
15854938Sheideman vprint("null_node_create: exists", NULLTOV(ap));
15954751Sjohnh #endif
16054938Sheideman /* VREF(aliasvp); --- done in null_node_find */
16154751Sjohnh } else {
16254751Sjohnh int error;
16354751Sjohnh
16454751Sjohnh /*
16554751Sjohnh * Get new vnode.
16654751Sjohnh */
16754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
16854938Sheideman printf("null_node_create: create new alias vnode\n");
16954751Sjohnh #endif
17054751Sjohnh
17154751Sjohnh /*
17254754Sjohnh * Make new vnode reference the null_node.
17354751Sjohnh */
17454951Sheideman if (error = null_node_alloc(mp, lowervp, &aliasvp))
17554951Sheideman return error;
17654751Sjohnh
17754751Sjohnh /*
17854751Sjohnh * aliasvp is already VREF'd by getnewvnode()
17954751Sjohnh */
18054751Sjohnh }
18154751Sjohnh
18254938Sheideman vrele(lowervp);
18354751Sjohnh
18454951Sheideman #ifdef DIAGNOSTIC
18554938Sheideman if (lowervp->v_usecount < 1) {
18654951Sheideman /* Should never happen... */
18767398Smkm vprint ("null_node_create: alias ", aliasvp);
18867398Smkm vprint ("null_node_create: lower ", lowervp);
18954938Sheideman panic ("null_node_create: lower has 0 usecount.");
19054938Sheideman };
19154951Sheideman #endif
19254938Sheideman
19354754Sjohnh #ifdef NULLFS_DIAGNOSTIC
19454938Sheideman vprint("null_node_create: alias", aliasvp);
19554938Sheideman vprint("null_node_create: lower", lowervp);
19654751Sjohnh #endif
19754751Sjohnh
19854751Sjohnh *newvpp = aliasvp;
19954751Sjohnh return (0);
20054751Sjohnh }
20154754Sjohnh #ifdef NULLFS_DIAGNOSTIC
20254751Sjohnh struct vnode *
null_checkvp(vp,fil,lno)20354754Sjohnh null_checkvp(vp, fil, lno)
20454751Sjohnh struct vnode *vp;
20554751Sjohnh char *fil;
20654751Sjohnh int lno;
20754751Sjohnh {
20854938Sheideman struct null_node *a = VTONULL(vp);
20955025Smckusick #ifdef notyet
21054938Sheideman /*
21154938Sheideman * Can't do this check because vop_reclaim runs
21254938Sheideman * with a funny vop vector.
21354938Sheideman */
21454938Sheideman if (vp->v_op != null_vnodeop_p) {
21554938Sheideman printf ("null_checkvp: on non-null-node\n");
21654938Sheideman while (null_checkvp_barrier) /*WAIT*/ ;
21754938Sheideman panic("null_checkvp");
21854938Sheideman };
21954938Sheideman #endif
22054938Sheideman if (a->null_lowervp == NULL) {
22154766Sjohnh /* Should never happen */
22254751Sjohnh int i; u_long *p;
22354751Sjohnh printf("vp = %x, ZERO ptr\n", vp);
22454751Sjohnh for (p = (u_long *) a, i = 0; i < 8; i++)
22554751Sjohnh printf(" %x", p[i]);
22654751Sjohnh printf("\n");
22754938Sheideman /* wait for debugger */
22854938Sheideman while (null_checkvp_barrier) /*WAIT*/ ;
22954754Sjohnh panic("null_checkvp");
23054751Sjohnh }
23154938Sheideman if (a->null_lowervp->v_usecount < 1) {
23254938Sheideman int i; u_long *p;
23354938Sheideman printf("vp = %x, unref'ed lowervp\n", vp);
23454938Sheideman for (p = (u_long *) a, i = 0; i < 8; i++)
23554938Sheideman printf(" %x", p[i]);
23654938Sheideman printf("\n");
23754938Sheideman /* wait for debugger */
23854938Sheideman while (null_checkvp_barrier) /*WAIT*/ ;
23954938Sheideman panic ("null with unref'ed lowervp");
24054938Sheideman };
24155025Smckusick #ifdef notyet
24254938Sheideman printf("null %x/%d -> %x/%d [%s, %d]\n",
24354938Sheideman NULLTOV(a), NULLTOV(a)->v_usecount,
24454766Sjohnh a->null_lowervp, a->null_lowervp->v_usecount,
24554751Sjohnh fil, lno);
24654938Sheideman #endif
24754754Sjohnh return a->null_lowervp;
24854751Sjohnh }
24954751Sjohnh #endif
250