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 [email protected]
  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;
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to