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"); _______________________________________________ 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"