diff options
-rw-r--r-- | sys/fs/nfsclient/nfs_clnode.c | 21 | ||||
-rw-r--r-- | sys/fs/nfsclient/nfsnode.h | 3 |
2 files changed, 22 insertions, 2 deletions
diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index d15de6e..5e7185d 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -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 *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 1d1c89c..c29805d 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 <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; |