nfs_lookup doesn't set PDIRUNLOCK?

Brian Buchanan bwb at holo.org
Sun Aug 1 11:29:23 PDT 2004


I think I've tracked down my problem with nullfs layered over NFS causing
deadlocks on 4.10.  The nullfs code blindly trusts the lower layer to
correctly set the PDIRUNLOCK flag to know whether it has released the lock
on the parent directory, and NFS doesn't seem to have any code that
manipulates this flag.  The result is that nullfs's VOP_LOOKUP doesn't
release the lock on the upper layer.

Everything else that I've looked at (FFS, SMBFS, MSDOSFS, etc.) seems to
play nice with PDIRUNLOCK, though I haven't actually tested with anything
other than FFS and NFS.  NFS in -CURRENT also appears to use PDIRUNLOCK.

I thought I was missing something here, wondering "how did NFS ever
work?!", until I discovered that NFS in -STABLE just isn't locked.  Oh.

But why do we have PDIRUNLOCK, anyway?  Shouldn't everything be following
the locking protocol described in VOP_LOOKUP(9)?

Also, there appears to be a separate logic bug in the -CURRENT nullfs code
(and tjr's nullfs patch) that results in the same deadlock if the lower
layer did not export a lock.

Here's a patch against -STABLE that should make things better.  This
is obviously not the right solution, but it is easier than hacking
on NFS.

nullfs in -CURRENT could use the "... dvp->v_vnlock == NULL || ..." part
of the fix, too, to fix the no-exported-lock bug.  Of course, everything
in current might be exporting a lock by now.

Index: null_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/miscfs/nullfs/Attic/null_vnops.c,v
retrieving revision 1.38.2.6
diff -u -r1.38.2.6 null_vnops.c
--- null_vnops.c	31 Jul 2002 00:32:28 -0000	1.38.2.6
+++ null_vnops.c	1 Aug 2004 18:08:49 -0000
@@ -376,17 +376,26 @@
 	ldvp = NULLVPTOLOWERVP(dvp);
 	vp = lvp = NULL;
 	error = VOP_LOOKUP(ldvp, &lvp, cnp);
+
+	/*
+	 * We should be relying on PDIRUNLOCK here, but we can't
+	 * currently trust the underlying filesystem to set it.
+	 * Instead, we'll determine whether the lower vnode should
+	 * have been unlocked per VOP_LOOKUP(9).
+	 *
+	 * Also, only release our lock if it is not shared with
+	 * the lower vnode.
+	 */
+	if ((error == 0 || error == EJUSTRETURN) &&
+	    !((flags & ISLASTCN) && (flags & LOCKPARENT)) &&
+	    (dvp->v_vnlock == NULL || dvp->v_vnlock != ldvp->v_vnlock))
+		VOP_UNLOCK(dvp, LK_THISLAYER, p);
+
 	if (error == EJUSTRETURN && (flags & ISLASTCN) &&
 	    (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
 	    (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
 		error = EROFS;

-	/*
-	 * Rely only on the PDIRUNLOCK flag which should be carefully
-	 * tracked by underlying filesystem.
-	 */
-	if (cnp->cn_flags & PDIRUNLOCK)
-		VOP_UNLOCK(dvp, LK_THISLAYER, p);
 	if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) {
 		if (ldvp == lvp) {
 			*ap->a_vpp = dvp;


-- 
Brian Buchanan, CISSP                                         bwb at holo.org
--------------------------------------------------------------------------
FreeBSD - The Power to Serve                        http://www.freebsd.org




More information about the freebsd-stable mailing list