diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index d15de6e9c7b..5e7185df212 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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 *fhp, int fhsize, struct nfsnode **npp, 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 *ap) */ 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; diff --git a/sys/fs/nfsclient/nfsnode.h b/sys/fs/nfsclient/nfsnode.h index 1d1c89c7d4b..c29805d5efe 100644 --- a/sys/fs/nfsclient/nfsnode.h +++ b/sys/fs/nfsclient/nfsnode.h @@ -35,11 +35,14 @@ #ifndef _NFSCLIENT_NFSNODE_H_ #define _NFSCLIENT_NFSNODE_H_ +#include + /* * 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;