Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Oct 2016 17:39:40 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r307378 - stable/10/sys/dev/iscsi
Message-ID:  <201610151739.u9FHdeZc045374@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201610151739.u9FHdeZc045374>