summaryrefslogtreecommitdiffstats
path: root/sys/fs/nullfs/null_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nullfs/null_subr.c')
-rw-r--r--sys/fs/nullfs/null_subr.c38
1 files changed, 29 insertions, 9 deletions
diff --git a/sys/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c
index 3671f0a..efb1357 100644
--- a/sys/fs/nullfs/null_subr.c
+++ b/sys/fs/nullfs/null_subr.c
@@ -99,6 +99,7 @@ nullfs_uninit(vfsp)
/*
* Return a VREF'ed alias for lower vnode if already exists, else 0.
+ * Lower vnode should be locked on entry and will be left locked on exit.
*/
static struct vnode *
null_node_find(mp, lowervp)
@@ -128,10 +129,15 @@ loop:
* stuff, but we don't want to lock
* the lower node.
*/
- if (vget(vp, 0, p)) {
+ if (vget(vp, LK_EXCLUSIVE | LK_CANRECURSE, p)) {
printf ("null_node_find: vget failed.\n");
goto loop;
};
+ /*
+ * Now we got both vnodes locked, so release the
+ * lower one.
+ */
+ VOP_UNLOCK(lowervp, 0, p);
return (vp);
}
}
@@ -184,14 +190,30 @@ null_node_alloc(mp, lowervp, vpp)
*/
othervp = null_node_find(mp, lowervp);
if (othervp) {
+ vp->v_data = NULL;
FREE(xp, M_NULLFSNODE);
vp->v_type = VBAD; /* node is discarded */
- vp->v_usecount = 0; /* XXX */
+ vrele(vp);
*vpp = othervp;
return 0;
};
+
+ /*
+ * From NetBSD:
+ * Now lock the new node. We rely on the fact that we were passed
+ * a locked vnode. If the lower node is exporting a struct lock
+ * (v_vnlock != NULL) then we just set the upper v_vnlock to the
+ * lower one, and both are now locked. If the lower node is exporting
+ * NULL, then we copy that up and manually lock the new vnode.
+ */
+
lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, p);
- VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */
+ vp->v_vnlock = lowervp->v_vnlock;
+ error = VOP_LOCK(vp, LK_EXCLUSIVE | LK_THISLAYER, p);
+ if (error)
+ panic("null_node_alloc: can't lock new vnode\n");
+
+ VREF(lowervp);
hd = NULL_NHASH(lowervp);
LIST_INSERT_HEAD(hd, xp, null_hash);
lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
@@ -200,9 +222,9 @@ null_node_alloc(mp, lowervp, vpp)
/*
- * 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.
+ * Try to find an existing null_node vnode refering to the given underlying
+ * vnode (which should be locked). If no vnode found, create a new null_node
+ * vnode which contains a reference to the lower vnode.
*/
int
null_node_create(mp, lowervp, newvpp)
@@ -218,10 +240,10 @@ null_node_create(mp, lowervp, newvpp)
* null_node_find has taken another reference
* to the alias vnode.
*/
+ vrele(lowervp);
#ifdef NULLFS_DEBUG
vprint("null_node_create: exists", aliasvp);
#endif
- /* VREF(aliasvp); --- done in null_node_find */
} else {
int error;
@@ -242,8 +264,6 @@ null_node_create(mp, lowervp, newvpp)
*/
}
- vrele(lowervp);
-
#ifdef DIAGNOSTIC
if (lowervp->v_usecount < 1) {
/* Should never happen... */
OpenPOWER on IntegriCloud