Author: rmacklem
Date: Thu Nov 17 01:02:45 2011
New Revision: 227601
URL: http://svn.freebsd.org/changeset/base/227601

Log:
  MFC: r227059
  Both a crash reported on freebsd-current on Oct. 18 under the
  subject heading "mtx_lock() of destroyed mutex on NFS" and
  PR# 156168 appear to be caused by clnt_dg_destroy() closing
  down the socket prematurely. When to close down the socket
  is controlled by a reference count (cs_refs), but clnt_dg_create()
  checks for sb_upcall being non-NULL to decide if a new socket
  is needed. I believe the crashes were caused by the following race:
    clnt_dg_destroy() finds cs_refs == 0 and decides to delete socket
    clnt_dg_destroy() then loses race with clnt_dg_create() for
      acquisition of the SOCKBUF_LOCK()
    clnt_dg_create() finds sb_upcall != NULL and increments cs_refs to 1
    clnt_dg_destroy() then acquires SOCKBUF_LOCK(), sets sb_upcall to
      NULL and destroys socket
  
  This patch fixes the above race by changing clnt_dg_destroy() so
  that it acquires SOCKBUF_LOCK() before testing cs_refs.
  
  Tested by:    bz
  Reviewed by:  dfr

Modified:
  stable/8/sys/rpc/clnt_dg.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/rpc/clnt_dg.c
==============================================================================
--- stable/8/sys/rpc/clnt_dg.c  Thu Nov 17 01:02:33 2011        (r227600)
+++ stable/8/sys/rpc/clnt_dg.c  Thu Nov 17 01:02:45 2011        (r227601)
@@ -1001,12 +1001,12 @@ clnt_dg_destroy(CLIENT *cl)
        cs = cu->cu_socket->so_rcv.sb_upcallarg;
        clnt_dg_close(cl);
 
+       SOCKBUF_LOCK(&cu->cu_socket->so_rcv);
        mtx_lock(&cs->cs_lock);
 
        cs->cs_refs--;
        if (cs->cs_refs == 0) {
                mtx_unlock(&cs->cs_lock);
-               SOCKBUF_LOCK(&cu->cu_socket->so_rcv);
                soupcall_clear(cu->cu_socket, SO_RCV);
                clnt_dg_upcallsdone(cu->cu_socket, cs);
                SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv);
@@ -1015,6 +1015,7 @@ clnt_dg_destroy(CLIENT *cl)
                lastsocketref = TRUE;
        } else {
                mtx_unlock(&cs->cs_lock);
+               SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv);
                lastsocketref = FALSE;
        }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to