Author: mav
Date: Sat Oct 15 17:39:40 2016
New Revision: 307378
URL: https://svnweb.freebsd.org/changeset/base/307378

Log:
  MFC r282970: Close some potential races around socket start/close.
  
  There are some reports about panics on ic->ic_socket NULL derefence.
  This kind of races is the only way I can imagine it to happen.

Modified:
  stable/10/sys/dev/iscsi/icl.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/iscsi/icl.c
==============================================================================
--- stable/10/sys/dev/iscsi/icl.c       Sat Oct 15 16:29:06 2016        
(r307377)
+++ stable/10/sys/dev/iscsi/icl.c       Sat Oct 15 17:39:40 2016        
(r307378)
@@ -746,10 +746,6 @@ icl_receive_thread(void *arg)
        ic = arg;
        so = ic->ic_socket;
 
-       ICL_CONN_LOCK(ic);
-       ic->ic_receive_running = true;
-       ICL_CONN_UNLOCK(ic);
-
        for (;;) {
                if (ic->ic_disconnecting) {
                        //ICL_DEBUG("terminating");
@@ -971,8 +967,6 @@ icl_send_thread(void *arg)
        STAILQ_INIT(&queue);
 
        ICL_CONN_LOCK(ic);
-       ic->ic_send_running = true;
-
        for (;;) {
                for (;;) {
                        /*
@@ -1224,35 +1218,45 @@ icl_conn_start(struct icl_conn *ic)
        }
 
        /*
+        * Register socket upcall, to get notified about incoming PDUs
+        * and free space to send outgoing ones.
+        */
+       SOCKBUF_LOCK(&ic->ic_socket->so_snd);
+       soupcall_set(ic->ic_socket, SO_SND, icl_soupcall_send, ic);
+       SOCKBUF_UNLOCK(&ic->ic_socket->so_snd);
+       SOCKBUF_LOCK(&ic->ic_socket->so_rcv);
+       soupcall_set(ic->ic_socket, SO_RCV, icl_soupcall_receive, ic);
+       SOCKBUF_UNLOCK(&ic->ic_socket->so_rcv);
+
+       /*
         * Start threads.
         */
+       ICL_CONN_LOCK(ic);
+       ic->ic_send_running = ic->ic_receive_running = true;
+       ICL_CONN_UNLOCK(ic);
        error = kthread_add(icl_send_thread, ic, NULL, NULL, 0, 0, "%stx",
            ic->ic_name);
        if (error != 0) {
                ICL_WARN("kthread_add(9) failed with error %d", error);
+               ICL_CONN_LOCK(ic);
+               ic->ic_send_running = ic->ic_receive_running = false;
+               cv_signal(&ic->ic_send_cv);
+               ICL_CONN_UNLOCK(ic);
                icl_conn_close(ic);
                return (error);
        }
-
        error = kthread_add(icl_receive_thread, ic, NULL, NULL, 0, 0, "%srx",
            ic->ic_name);
        if (error != 0) {
                ICL_WARN("kthread_add(9) failed with error %d", error);
+               ICL_CONN_LOCK(ic);
+               ic->ic_receive_running = false;
+               cv_signal(&ic->ic_send_cv);
+               ICL_CONN_UNLOCK(ic);
                icl_conn_close(ic);
                return (error);
        }
 
-       /*
-        * Register socket upcall, to get notified about incoming PDUs
-        * and free space to send outgoing ones.
-        */
-       SOCKBUF_LOCK(&ic->ic_socket->so_snd);
-       soupcall_set(ic->ic_socket, SO_SND, icl_soupcall_send, ic);
-       SOCKBUF_UNLOCK(&ic->ic_socket->so_snd);
-       SOCKBUF_LOCK(&ic->ic_socket->so_rcv);
-       soupcall_set(ic->ic_socket, SO_RCV, icl_soupcall_receive, ic);
-       SOCKBUF_UNLOCK(&ic->ic_socket->so_rcv);
-
        return (0);
 }
 
@@ -1306,46 +1310,42 @@ void
 icl_conn_close(struct icl_conn *ic)
 {
        struct icl_pdu *pdu;
+       struct socket *so;
 
-       ICL_CONN_LOCK_ASSERT_NOT(ic);
-
-       ICL_CONN_LOCK(ic);
-       if (ic->ic_socket == NULL) {
-               ICL_CONN_UNLOCK(ic);
-               return;
-       }
-
-       /*
-        * Deregister socket upcalls.
-        */
-       ICL_CONN_UNLOCK(ic);
-       SOCKBUF_LOCK(&ic->ic_socket->so_snd);
-       if (ic->ic_socket->so_snd.sb_upcall != NULL)
-               soupcall_clear(ic->ic_socket, SO_SND);
-       SOCKBUF_UNLOCK(&ic->ic_socket->so_snd);
-       SOCKBUF_LOCK(&ic->ic_socket->so_rcv);
-       if (ic->ic_socket->so_rcv.sb_upcall != NULL)
-               soupcall_clear(ic->ic_socket, SO_RCV);
-       SOCKBUF_UNLOCK(&ic->ic_socket->so_rcv);
        ICL_CONN_LOCK(ic);
 
-       ic->ic_disconnecting = true;
-
        /*
         * Wake up the threads, so they can properly terminate.
         */
+       ic->ic_disconnecting = true;
        while (ic->ic_receive_running || ic->ic_send_running) {
-               //ICL_DEBUG("waiting for send/receive threads to terminate");
                cv_signal(&ic->ic_receive_cv);
                cv_signal(&ic->ic_send_cv);
                cv_wait(&ic->ic_send_cv, ic->ic_lock);
        }
-       //ICL_DEBUG("send/receive threads terminated");
 
+       /* Some other thread could close the connection same time. */
+       so = ic->ic_socket;
+       if (so == NULL) {
+               ICL_CONN_UNLOCK(ic);
+               return;
+       }
+       ic->ic_socket = NULL;
+
+       /*
+        * Deregister socket upcalls.
+        */
        ICL_CONN_UNLOCK(ic);
-       soclose(ic->ic_socket);
+       SOCKBUF_LOCK(&so->so_snd);
+       if (so->so_snd.sb_upcall != NULL)
+               soupcall_clear(so, SO_SND);
+       SOCKBUF_UNLOCK(&so->so_snd);
+       SOCKBUF_LOCK(&so->so_rcv);
+       if (so->so_rcv.sb_upcall != NULL)
+               soupcall_clear(so, SO_RCV);
+       SOCKBUF_UNLOCK(&so->so_rcv);
+       soclose(so);
        ICL_CONN_LOCK(ic);
-       ic->ic_socket = NULL;
 
        if (ic->ic_receive_pdu != NULL) {
                //ICL_DEBUG("freeing partially received PDU");
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to