From owner-svn-src-all@FreeBSD.ORG Tue Aug 2 11:24:42 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D7D53106564A; Tue, 2 Aug 2011 11:24:42 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id AE9BA8FC14; Tue, 2 Aug 2011 11:24:42 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p72BOgIr047933; Tue, 2 Aug 2011 11:24:42 GMT (envelope-from rmacklem@svn.freebsd.org) Received: (from rmacklem@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p72BOgEU047930; Tue, 2 Aug 2011 11:24:42 GMT (envelope-from rmacklem@svn.freebsd.org) Message-Id: <201108021124.p72BOgEU047930@svn.freebsd.org> From: Rick Macklem Date: Tue, 2 Aug 2011 11:24:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r224604 - head/sys/nfsclient X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Aug 2011 11:24:42 -0000 Author: rmacklem Date: Tue Aug 2 11:24:42 2011 New Revision: 224604 URL: http://svn.freebsd.org/changeset/base/224604 Log: Fix a LOR in the NFS client which could cause a deadlock. This was reported to the mailing list freebsd-net@freebsd.org on July 21, 2011 under the subject "LOR with nfsclient sillyrename". The LOR occurred when nfs_inactive() called vrele(sp->s_dvp) while holding the vnode lock on the file in s_dvp. This patch modifies the client so that it performs the vrele(sp->s_dvp) as a separate task to avoid the LOR. This fix was discussed with jhb@ and kib@, who both proposed variations of it. Tested by: pho, jlott at averesystems.com Submitted by: jhb (earlier version) Reviewed by: kib Approved by: re (kib) MFC after: 2 weeks Modified: head/sys/nfsclient/nfs_node.c head/sys/nfsclient/nfsnode.h Modified: head/sys/nfsclient/nfs_node.c ============================================================================== --- head/sys/nfsclient/nfs_node.c Tue Aug 2 11:07:47 2011 (r224603) +++ head/sys/nfsclient/nfs_node.c Tue Aug 2 11:24:42 2011 (r224604) @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -59,6 +60,8 @@ __FBSDID("$FreeBSD$"); static uma_zone_t nfsnode_zone; +static void nfs_freesillyrename(void *arg, __unused int pending); + #define TRUE 1 #define FALSE 0 @@ -185,6 +188,20 @@ nfs_nget(struct mount *mntp, nfsfh_t *fh return (0); } +/* + * Do the vrele(sp->s_dvp) as a separate task in order to avoid a + * deadlock because of a LOR when vrele() locks the directory vnode. + */ +static void +nfs_freesillyrename(void *arg, __unused int pending) +{ + struct sillyrename *sp; + + sp = arg; + vrele(sp->s_dvp); + free(sp, M_NFSREQ); +} + int nfs_inactive(struct vop_inactive_args *ap) { @@ -207,8 +224,8 @@ nfs_inactive(struct vop_inactive_args *a */ (sp->s_removeit)(sp); crfree(sp->s_cred); - vrele(sp->s_dvp); - free((caddr_t)sp, M_NFSREQ); + TASK_INIT(&sp->s_task, 0, nfs_freesillyrename, sp); + taskqueue_enqueue(taskqueue_thread, &sp->s_task); mtx_lock(&np->n_mtx); } np->n_flag &= NMODIFIED; Modified: head/sys/nfsclient/nfsnode.h ============================================================================== --- head/sys/nfsclient/nfsnode.h Tue Aug 2 11:07:47 2011 (r224603) +++ head/sys/nfsclient/nfsnode.h Tue Aug 2 11:24:42 2011 (r224604) @@ -36,6 +36,7 @@ #ifndef _NFSCLIENT_NFSNODE_H_ #define _NFSCLIENT_NFSNODE_H_ +#include #if !defined(_NFSCLIENT_NFS_H_) && !defined(_KERNEL) #include #endif @@ -45,6 +46,7 @@ * can be removed by nfs_inactive() */ struct sillyrename { + struct task s_task; struct ucred *s_cred; struct vnode *s_dvp; int (*s_removeit)(struct sillyrename *sp);