Date: Tue, 2 Aug 2011 11:28:42 +0000 (UTC) From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r224606 - head/sys/fs/nfsclient Message-ID: <201108021128.p72BSgiC048179@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rmacklem Date: Tue Aug 2 11:28:42 2011 New Revision: 224606 URL: http://svn.freebsd.org/changeset/base/224606 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/fs/nfsclient/nfs_clnode.c head/sys/fs/nfsclient/nfsnode.h Modified: head/sys/fs/nfsclient/nfs_clnode.c ============================================================================== --- head/sys/fs/nfsclient/nfs_clnode.c Tue Aug 2 11:28:33 2011 (r224605) +++ head/sys/fs/nfsclient/nfs_clnode.c Tue Aug 2 11:28:42 2011 (r224606) @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/socket.h> #include <sys/sysctl.h> +#include <sys/taskqueue.h> #include <sys/vnode.h> #include <vm/uma.h> @@ -65,6 +66,8 @@ MALLOC_DECLARE(M_NEWNFSREQ); uma_zone_t newnfsnode_zone; +static void nfs_freesillyrename(void *arg, __unused int pending); + void ncl_nhinit(void) { @@ -186,6 +189,20 @@ ncl_nget(struct mount *mntp, u_int8_t *f 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_NEWNFSREQ); +} + int ncl_inactive(struct vop_inactive_args *ap) { @@ -220,8 +237,8 @@ ncl_inactive(struct vop_inactive_args *a */ ncl_removeit(sp, vp); crfree(sp->s_cred); - vrele(sp->s_dvp); - FREE((caddr_t)sp, M_NEWNFSREQ); + 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/fs/nfsclient/nfsnode.h ============================================================================== --- head/sys/fs/nfsclient/nfsnode.h Tue Aug 2 11:28:33 2011 (r224605) +++ head/sys/fs/nfsclient/nfsnode.h Tue Aug 2 11:28:42 2011 (r224606) @@ -35,11 +35,14 @@ #ifndef _NFSCLIENT_NFSNODE_H_ #define _NFSCLIENT_NFSNODE_H_ +#include <sys/_task.h> + /* * Silly rename structure that hangs off the nfsnode until the name * can be removed by nfs_inactive() */ struct sillyrename { + struct task s_task; struct ucred *s_cred; struct vnode *s_dvp; long s_namlen;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201108021128.p72BSgiC048179>