svn commit: r282970 - head/sys/dev/iscsi
Alexander Motin
mav at FreeBSD.org
Fri May 15 13:36:51 UTC 2015
Author: mav
Date: Fri May 15 13:36:50 2015
New Revision: 282970
URL: https://svnweb.freebsd.org/changeset/base/282970
Log:
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.
MFC after: 2 weeks
Modified:
head/sys/dev/iscsi/icl_soft.c
Modified: head/sys/dev/iscsi/icl_soft.c
==============================================================================
--- head/sys/dev/iscsi/icl_soft.c Fri May 15 13:04:14 2015 (r282969)
+++ head/sys/dev/iscsi/icl_soft.c Fri May 15 13:36:50 2015 (r282970)
@@ -773,10 +773,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");
@@ -998,8 +994,6 @@ icl_send_thread(void *arg)
STAILQ_INIT(&queue);
ICL_CONN_LOCK(ic);
- ic->ic_send_running = true;
-
for (;;) {
for (;;) {
/*
@@ -1275,35 +1269,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_soft_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_soft_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);
}
@@ -1357,46 +1361,42 @@ void
icl_soft_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");
More information about the svn-src-all
mailing list