Module Name:    src
Committed By:   yamt
Date:           Sun May 10 05:18:26 UTC 2009

Modified Files:
        src/sys/nfs: nfs_vnops.c

Log Message:
nfs_lookup: vn_lock the vnode returned by cache_lookup_raw
before feeding it to VOP_GETATTR.  it's necessary because the vnode might
be being cleaned by getcleanvnode.

it's an instance of more general races between vnode reclaim and
unlocked VOPs.  however, this one happens somewhat often because it can be
triggered by getnewvnode rather than revoke.


To generate a diff of this commit:
cvs rdiff -u -r1.277 -r1.278 src/sys/nfs/nfs_vnops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/nfs/nfs_vnops.c
diff -u src/sys/nfs/nfs_vnops.c:1.277 src/sys/nfs/nfs_vnops.c:1.278
--- src/sys/nfs/nfs_vnops.c:1.277	Sun May 10 03:51:43 2009
+++ src/sys/nfs/nfs_vnops.c	Sun May 10 05:18:26 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_vnops.c,v 1.277 2009/05/10 03:51:43 yamt Exp $	*/
+/*	$NetBSD: nfs_vnops.c,v 1.278 2009/05/10 05:18:26 yamt Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_vnops.c,v 1.277 2009/05/10 03:51:43 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_vnops.c,v 1.278 2009/05/10 05:18:26 yamt Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_nfs.h"
@@ -855,31 +855,30 @@
 		 * investigate the vnode returned by cache_lookup_raw.
 		 * if it isn't appropriate, do an rpc.
 		 */
-
 		newvp = *vpp;
+		if ((flags & ISDOTDOT) != 0) {
+			VOP_UNLOCK(dvp, 0);
+		}
+		error = vn_lock(newvp, LK_EXCLUSIVE);
+		if ((flags & ISDOTDOT) != 0) {
+			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
+		}
+		if (error != 0) {
+			/* newvp has been reclaimed. */
+			vrele(newvp);
+			*vpp = NULLVP;
+			goto dorpc;
+		}
 		if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred)
 		    && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
 			nfsstats.lookupcache_hits++;
-			if ((flags & ISDOTDOT) != 0) {
-				VOP_UNLOCK(dvp, 0);
-			}
-			error = vn_lock(newvp, LK_EXCLUSIVE);
-			if ((flags & ISDOTDOT) != 0) {
-				vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
-			}
-			if (error != 0) {
-				/* newvp has been revoked. */
-				vrele(newvp);
-				*vpp = NULLVP;
-				goto dorpc;
-			}
 			if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
 				cnp->cn_flags |= SAVENAME;
 			KASSERT(newvp->v_type != VNON);
 			return (0);
 		}
 		cache_purge1(newvp, NULL, PURGE_PARENTS);
-		vrele(newvp);
+		vput(newvp);
 		*vpp = NULLVP;
 	}
 dorpc:

Reply via email to