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.
This commit is contained in:
parent
84e868b269
commit
8276e4de1a
|
@ -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 @@ nfs_lookup(void *v)
|
|||
* 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:
|
||||
|
|
Loading…
Reference in New Issue