--- nfsclient/nfsnode.h.sav 2011-07-22 15:31:11.000000000 -0400 +++ nfsclient/nfsnode.h 2011-07-22 15:32:54.000000000 -0400 @@ -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); --- nfsclient/nfs_node.c.sav 2011-07-22 15:33:04.000000000 -0400 +++ nfsclient/nfs_node.c 2011-07-22 16:31:45.000000000 -0400 @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: head/sys/nfsclient/n #include #include #include +#include #include #include @@ -59,6 +60,8 @@ __FBSDID("$FreeBSD: head/sys/nfsclient/n 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;