* Copyright (c) 1992 The Regents of the University of California
* Copyright (c) 1990, 1992 Jan-Simon Pendry
* This code is derived from software donated to Berkeley by
* %sccs.include.redist.c%
* @(#)lofs_subr.c 1.2 (Berkeley) 6/18/92
* $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
#define NNULLNODECACHE 16
#define NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1))
* Each cache entry holds a reference to the lower vnode
* along with a pointer to the alias vnode. When an
* entry is added the lower vnode is VREF'd. When the
* alias is removed the lower vnode is vrele'd.
struct null_node
*ac_forw
;
struct null_node
*ac_back
;
static struct null_node_cache null_node_cache
[NNULLNODECACHE
];
* Initialise cache headers
struct null_node_cache
*ac
;
printf("nullfs_init\n"); /* printed during system boot */
for (ac
= null_node_cache
; ac
< null_node_cache
+ NNULLNODECACHE
; ac
++)
ac
->ac_forw
= ac
->ac_back
= (struct null_node
*) ac
;
* Compute hash list for given lower vnode
static struct null_node_cache
*
return (&null_node_cache
[NULL_NHASH(lowervp
)]);
* XXX - this should go elsewhere.
* Just like vget, but with no lock at the end.
register struct vnode
*vp
;
extern struct vnode
*vfreeh
, **vfreet
;
register struct vnode
*vq
;
if (vp
->v_flag
& VXLOCK
) {
sleep((caddr_t
)vp
, PINOD
);
if (vp
->v_usecount
== 0) {
vq
->v_freeb
= vp
->v_freeb
;
* Return a VREF'ed alias for lower vnode if already exists, else 0.
null_node_find(mp
, lowervp
)
struct null_node_cache
*hd
;
* Find hash base, and then search the (two-way) linked
* list looking for a null_node structure which is referencing
* the lower vnode. If found, the increment the null_node
* reference count (but NOT the lower vnode's VREF counter).
hd
= null_node_hash(lowervp
);
for (a
= hd
->ac_forw
; a
!= (struct null_node
*) hd
; a
= a
->null_forw
) {
if (a
->null_lowervp
== lowervp
&& NULLTOV(a
)->v_mount
== mp
) {
* We need vget for the VXLOCK
* stuff, but we don't want to lock
printf ("null_node_find: vget failed.\n");
* Make a new null_node node.
* Vp is the alias vnode, lofsvp is the lower vnode.
* Maintain a reference to (lowervp).
null_node_alloc(mp
, lowervp
, vpp
)
struct null_node_cache
*hd
;
struct vnode
*othervp
, *vp
;
if (error
= getnewvnode(VT_UFS
, mp
, null_vnodeop_p
, vpp
))
return (error
); /* XXX: VT_NULL above */
MALLOC(xp
, struct null_node
*, sizeof(struct null_node
), M_TEMP
, M_WAITOK
);
vp
->v_type
= lowervp
->v_type
;
xp
->null_lowervp
= lowervp
;
* Before we insert our new node onto the hash chains,
* check to see if someone else has beaten us to it.
* (We could have slept in MALLOC.)
if (othervp
= null_node_find(lowervp
)) {
vp
->v_type
= VBAD
; /* node is discarded */
vp
->v_usecount
= 0; /* XXX */
VREF(lowervp
); /* Extra VREF will be vrele'd in null_node_create */
hd
= null_node_hash(lowervp
);
* Try to find an existing null_node vnode refering
* to it, otherwise make a new null_node vnode which
* contains a reference to the lower vnode.
null_node_create(mp
, lowervp
, newvpp
)
if (aliasvp
= null_node_find(mp
, lowervp
)) {
* null_node_find has taken another reference
vprint("null_node_create: exists", NULLTOV(ap
));
/* VREF(aliasvp); --- done in null_node_find */
printf("null_node_create: create new alias vnode\n");
* Make new vnode reference the null_node.
if (error
= null_node_alloc(mp
, lowervp
, &aliasvp
))
* aliasvp is already VREF'd by getnewvnode()
if (lowervp
->v_usecount
< 1) {
/* Should never happen... */
vprint ("null_node_create: alias ");
vprint ("null_node_create: lower ");
printf ("null_node_create: lower has 0 usecount.\n");
panic ("null_node_create: lower has 0 usecount.");
vprint("null_node_create: alias", aliasvp
);
vprint("null_node_create: lower", lowervp
);
null_checkvp(vp
, fil
, lno
)
struct null_node
*a
= VTONULL(vp
);
* Can't do this check because vop_reclaim runs
* with a funny vop vector.
if (vp
->v_op
!= null_vnodeop_p
) {
printf ("null_checkvp: on non-null-node\n");
while (null_checkvp_barrier
) /*WAIT*/ ;
if (a
->null_lowervp
== NULL
) {
/* Should never happen */
printf("vp = %x, ZERO ptr\n", vp
);
for (p
= (u_long
*) a
, i
= 0; i
< 8; i
++)
while (null_checkvp_barrier
) /*WAIT*/ ;
if (a
->null_lowervp
->v_usecount
< 1) {
printf("vp = %x, unref'ed lowervp\n", vp
);
for (p
= (u_long
*) a
, i
= 0; i
< 8; i
++)
while (null_checkvp_barrier
) /*WAIT*/ ;
panic ("null with unref'ed lowervp");
printf("null %x/%d -> %x/%d [%s, %d]\n",
NULLTOV(a
), NULLTOV(a
)->v_usecount
,
a
->null_lowervp
, a
->null_lowervp
->v_usecount
,