From 2595d6bead5c8c2d6eec6447e416c9636169016d Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 9 Feb 2010 00:46:26 -0800 Subject: [PATCH] kernel - NFS - fix deadlock in NFS client-side readdirplus * readdirplus holds a vnode lock while attempting to do a namecache lookup, which is not legal. Unlock the vnode while doing the lookup. --- sys/vfs/nfs/nfs_vnops.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sys/vfs/nfs/nfs_vnops.c b/sys/vfs/nfs/nfs_vnops.c index 0c05d0ad26..c68ff67041 100644 --- a/sys/vfs/nfs/nfs_vnops.c +++ b/sys/vfs/nfs/nfs_vnops.c @@ -2475,6 +2475,7 @@ int nfs_readdirplusrpc_uio(struct vnode *vp, struct uio *uiop) { int len, left; + int lkstatus; struct nfs_dirent *dp; u_int32_t *tl; struct vnode *newvp; @@ -2653,11 +2654,25 @@ nfs_readdirplusrpc_uio(struct vnode *vp, struct uio *uiop) nlc.nlc_namelen, nlc.nlc_namelen, nlc.nlc_nameptr); #endif + /* + * Work around a directory-vp/namecache + * deadlock. Namecache lookups should + * be run without any vp locks held. + */ + lkstatus = vn_islocked(vp); + if (lkstatus == LK_EXCLUSIVE || + lkstatus == LK_SHARED) { + vn_unlock(vp); + } nch = cache_nlookup(&dnch, &nlc); cache_setunresolved(&nch); nfs_cache_setvp(&nch, newvp, nfspos_cache_timeout); cache_put(&nch); + if (lkstatus == LK_EXCLUSIVE || + lkstatus == LK_SHARED) { + vn_lock(vp, lkstatus | LK_RETRY); + } } else { kprintf("Warning: NFS/rddirplus, " "UNABLE TO ENTER %*.*s\n", -- 2.11.4.GIT