Module Name:    src
Committed By:   mlelstv
Date:           Tue Sep 13 13:09:16 UTC 2022

Modified Files:
        src/sys/dev/iscsi: iscsi_globals.h iscsi_ioctl.c iscsi_main.c
            iscsi_rcv.c iscsi_send.c iscsi_utils.c

Log Message:
kill_session now uses the session id to avoid stale session pointers.
protect network socket with rwlock to handle recconnects.
always take over socket from iscsid to prevent leaks.
keep a good connection alive.
don't forget child device when config_detach fails.
fix locking when reassigning CCBs.
pducount is protected by lock, no need for atomic.
some code rework, refined debug messages.


To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/sys/dev/iscsi/iscsi_globals.h
cvs rdiff -u -r1.32 -r1.33 src/sys/dev/iscsi/iscsi_ioctl.c
cvs rdiff -u -r1.40 -r1.41 src/sys/dev/iscsi/iscsi_main.c
cvs rdiff -u -r1.25 -r1.26 src/sys/dev/iscsi/iscsi_rcv.c
cvs rdiff -u -r1.38 -r1.39 src/sys/dev/iscsi/iscsi_send.c
cvs rdiff -u -r1.27 -r1.28 src/sys/dev/iscsi/iscsi_utils.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/iscsi/iscsi_globals.h
diff -u src/sys/dev/iscsi/iscsi_globals.h:1.26 src/sys/dev/iscsi/iscsi_globals.h:1.27
--- src/sys/dev/iscsi/iscsi_globals.h:1.26	Sun Jun 21 23:08:16 2020
+++ src/sys/dev/iscsi/iscsi_globals.h	Tue Sep 13 13:09:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_globals.h,v 1.26 2020/06/21 23:08:16 chs Exp $	*/
+/*	$NetBSD: iscsi_globals.h,v 1.27 2022/09/13 13:09:16 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -37,6 +37,8 @@
 /* Includes we need in all files */
 
 #include <sys/param.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
 #include <sys/proc.h>
 #include <sys/conf.h>
 #include <sys/errno.h>
@@ -354,6 +356,8 @@ struct connection_s {
 
 	struct lwp			*c_threadobj;
 		/* proc/thread pointer of socket owner */
+
+	krwlock_t			c_sock_rw;
 	struct file			*c_sock;	/* the connection's socket */
 	session_t			*c_session;
 					/* back pointer to the owning session */
@@ -366,7 +370,7 @@ struct connection_s {
 	int				c_recover; /* recovery count */
 		/* (reset on first successful data transfer) */
 	volatile unsigned		c_usecount; /* number of active CCBs */
-	volatile unsigned		c_pducount; /* number of active PDUs */
+	unsigned			c_pducount; /* number of active PDUs */
 
 	bool				c_destroy; /* conn will be destroyed */
 	bool				c_in_session;
@@ -537,8 +541,8 @@ extern bool iscsi_hex_bignums;	/* Whethe
 #define DEBOUT(x) printf x
 #define DEB(lev,x) { if (iscsi_debug_level >= lev) printf x ;}
 #define DEBC(conn,lev,x) { if (iscsi_debug_level >= lev) { printf("S%dC%d: ", \
-				conn ? conn->c_session->s_id : -1, \
-				conn ? conn->c_id : -1); printf x ;}}
+			conn && conn->c_session ? conn->c_session->s_id : -1, \
+			conn ? conn->c_id : -1); printf x ;}}
 
 #define STATIC static
 
@@ -646,7 +650,7 @@ void iscsi_notify_cleanup(void);
 void add_event(iscsi_event_t, uint32_t, uint32_t, uint32_t);
 
 void kill_connection(connection_t *, uint32_t, int, bool);
-void kill_session(session_t *, uint32_t, int, bool);
+void kill_session(uint32_t, uint32_t, int, bool);
 int kill_all_sessions(void);
 void handle_connection_error(connection_t *, uint32_t, int);
 void add_connection_cleanup(connection_t *);

Index: src/sys/dev/iscsi/iscsi_ioctl.c
diff -u src/sys/dev/iscsi/iscsi_ioctl.c:1.32 src/sys/dev/iscsi/iscsi_ioctl.c:1.33
--- src/sys/dev/iscsi/iscsi_ioctl.c:1.32	Sun Jun 21 23:08:16 2020
+++ src/sys/dev/iscsi/iscsi_ioctl.c	Tue Sep 13 13:09:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_ioctl.c,v 1.32 2020/06/21 23:08:16 chs Exp $	*/
+/*	$NetBSD: iscsi_ioctl.c,v 1.33 2022/09/13 13:09:16 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -494,8 +494,8 @@ kill_connection(connection_t *conn, uint
 	if (recover &&
 	    !conn->c_destroy &&
 	    conn->c_recover > MAX_RECOVERY_ATTEMPTS) {
-		DEBC(conn, 1,
-			  ("Kill_connection: Too many recovery attempts, destroying\n"));
+		DEBC(conn, 1, ("Kill_connection: Too many recovery attempts, "
+		               "destroying\n"));
 		conn->c_destroy = TRUE;
 	}
 
@@ -547,6 +547,8 @@ kill_connection(connection_t *conn, uint
 			}
 			mutex_exit(&iscsi_cleanup_mtx);
 
+			DEBC(conn, 1, ("Send_logout for reason %d\n", logout));
+
 			connection_timeout_start(conn, CONNECTION_TIMEOUT);
 
 			if (!send_logout(conn, conn, logout, FALSE)) {
@@ -591,14 +593,24 @@ done:
  */
 
 void
-kill_session(session_t *sess, uint32_t status, int logout, bool recover)
+kill_session(uint32_t sid, uint32_t status, int logout, bool recover)
 {
+	session_t *sess;
 	connection_t *conn;
 
 	DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n",
-			sess->s_id, status, logout, recover));
+			sid, status, logout, recover));
 
 	mutex_enter(&iscsi_cleanup_mtx);
+
+	sess = find_session(sid);
+	if (sess == NULL) {
+		mutex_exit(&iscsi_cleanup_mtx);
+
+		DEB(5, ("Session %u already gone\n", sid));
+		return;
+	}
+
 	if (sess->s_terminating) {
 		mutex_exit(&iscsi_cleanup_mtx);
 
@@ -648,6 +660,13 @@ kill_session(session_t *sess, uint32_t s
 	sess->s_sessions.tqe_next = NULL;
 	sess->s_sessions.tqe_prev = NULL;
 
+	/*
+	 * If all connections are already gone, trigger cleanup
+	 * otherwise, the last connection will do this
+	 */
+	if (sess->s_active_connections == 0)
+		iscsi_notify_cleanup();
+
 	mutex_exit(&iscsi_cleanup_mtx);
 
 	/* kill all connections */
@@ -661,6 +680,7 @@ kill_session(session_t *sess, uint32_t s
 /*
  * create_connection:
  *    Create and init the necessary framework for a connection:
+ *       Take over userland socket
  *       Alloc the connection structure itself
  *       Copy connection parameters
  *       Create the send and receive threads
@@ -689,6 +709,9 @@ create_connection(iscsi_login_parameters
 	    sess->s_active_connections >= sess->s_MaxConnections) {
 		DEBOUT(("Too many connections (max = %d, curr = %d)\n",
 				sess->s_MaxConnections, sess->s_active_connections));
+		/* Always close descriptor */
+		fd_close(par->socket);
+
 		par->status = ISCSI_STATUS_MAXED_CONNECTIONS;
 		return EIO;
 	}
@@ -696,10 +719,35 @@ create_connection(iscsi_login_parameters
 	conn = malloc(sizeof(*conn), M_DEVBUF, M_WAITOK | M_ZERO);
 	if (conn == NULL) {
 		DEBOUT(("No mem for connection\n"));
+
+		/* Always close descriptor */
+		fd_close(par->socket);
+
 		par->status = ISCSI_STATUS_NO_RESOURCES;
 		return EIO;
 	}
 
+	rc = get_socket(par->socket, &conn->c_sock);
+	fd_close(par->socket);
+
+	if (rc) {
+		DEBOUT(("Invalid socket %d\n", par->socket));
+
+		callout_destroy(&conn->c_timeout);
+		rw_destroy(&conn->c_sock_rw);
+		cv_destroy(&conn->c_idle_cv);
+		cv_destroy(&conn->c_ccb_cv);
+		cv_destroy(&conn->c_pdu_cv);
+		cv_destroy(&conn->c_conn_cv);
+		mutex_destroy(&conn->c_lock);
+		free(conn, M_DEVBUF);
+		par->status = ISCSI_STATUS_INVALID_SOCKET;
+		return rc;
+	}
+
+	DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n",
+			par->socket, conn->c_sock));
+
 	mutex_enter(&iscsi_cleanup_mtx);
 	/* create a unique ID */
 	do {
@@ -721,6 +769,7 @@ create_connection(iscsi_login_parameters
 	cv_init(&conn->c_pdu_cv, "pdupool");
 	cv_init(&conn->c_ccb_cv, "ccbwait");
 	cv_init(&conn->c_idle_cv, "idle");
+	rw_init(&conn->c_sock_rw);
 
 	callout_init(&conn->c_timeout, CALLOUT_MPSAFE);
 	callout_setfunc(&conn->c_timeout, connection_timeout_co, conn);
@@ -729,25 +778,6 @@ create_connection(iscsi_login_parameters
 	init_sernum(&conn->c_StatSN_buf);
 	create_pdus(conn);
 
-	if ((rc = get_socket(par->socket, &conn->c_sock)) != 0) {
-		DEBOUT(("Invalid socket %d\n", par->socket));
-
-		callout_destroy(&conn->c_timeout);
-		cv_destroy(&conn->c_idle_cv);
-		cv_destroy(&conn->c_ccb_cv);
-		cv_destroy(&conn->c_pdu_cv);
-		cv_destroy(&conn->c_conn_cv);
-		mutex_destroy(&conn->c_lock);
-		free(conn, M_DEVBUF);
-		par->status = ISCSI_STATUS_INVALID_SOCKET;
-		return rc;
-	}
-	DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n",
-			par->socket, conn->c_sock));
-
-	/* close the file descriptor */
-	fd_close(par->socket);
-
 	conn->c_threadobj = l;
 	conn->c_login_par = par;
 
@@ -758,6 +788,7 @@ create_connection(iscsi_login_parameters
 		DEBOUT(("Can't create rcv thread (rc %d)\n", rc));
 
 		release_socket(conn->c_sock);
+		rw_destroy(&conn->c_sock_rw);
 		callout_destroy(&conn->c_timeout);
 		cv_destroy(&conn->c_idle_cv);
 		cv_destroy(&conn->c_ccb_cv);
@@ -791,6 +822,7 @@ create_connection(iscsi_login_parameters
 
 		release_socket(conn->c_sock);
 		callout_destroy(&conn->c_timeout);
+		rw_destroy(&conn->c_sock_rw);
 		cv_destroy(&conn->c_idle_cv);
 		cv_destroy(&conn->c_ccb_cv);
 		cv_destroy(&conn->c_pdu_cv);
@@ -868,27 +900,32 @@ recreate_connection(iscsi_login_paramete
 	    sess->s_active_connections >= sess->s_MaxConnections) {
 		DEBOUT(("Too many connections (max = %d, curr = %d)\n",
 			sess->s_MaxConnections, sess->s_active_connections));
+
+		/* Always close the desecriptor */
+		fd_close(par->socket);
+
 		par->status = ISCSI_STATUS_MAXED_CONNECTIONS;
 		return EIO;
 	}
 
-	/* close old socket */
+	rw_enter(&conn->c_sock_rw, RW_WRITER);
 	if (conn->c_sock != NULL) {
 		closef(conn->c_sock);
 		conn->c_sock = NULL;
 	}
+	rc = get_socket(par->socket, &conn->c_sock);
+	rw_exit(&conn->c_sock_rw);
+	fd_close(par->socket);
 
-	if ((rc = get_socket(par->socket, &conn->c_sock)) != 0) {
+	if (rc) {
 		DEBOUT(("Invalid socket %d\n", par->socket));
 		par->status = ISCSI_STATUS_INVALID_SOCKET;
 		return rc;
 	}
+
 	DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n",
 			par->socket, conn->c_sock));
 
-	/* close the file descriptor */
-	fd_close(par->socket);
-
 	conn->c_threadobj = l;
 	conn->c_login_par = par;
 	conn->c_terminating = ISCSI_STATUS_SUCCESS;
@@ -912,7 +949,7 @@ recreate_connection(iscsi_login_paramete
 	mutex_exit(&conn->c_lock);
 
 	if ((rc = send_login(conn)) != 0) {
-		DEBOUT(("Login failed (rc %d)\n", rc));
+		DEBC(conn, 0, ("Re-Login failed (rc %d)\n", rc));
 		while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
 			TAILQ_REMOVE(&old_waiting, ccb, ccb_chain);
 			wake_ccb(ccb, rc);
@@ -1121,7 +1158,7 @@ login(iscsi_login_parameters_t *par, str
 		DEB(1, ("Login: map session %d\n", sess->s_id));
 		if (!map_session(sess, dev)) {
 			DEB(1, ("Login: map session %d failed\n", sess->s_id));
-			kill_session(sess, ISCSI_STATUS_MAP_FAILED,
+			kill_session(par->session_id, ISCSI_STATUS_MAP_FAILED,
 					LOGOUT_SESSION, FALSE);
 			par->status = ISCSI_STATUS_MAP_FAILED;
 			return;
@@ -1156,7 +1193,9 @@ logout(iscsi_logout_parameters_t *par)
 	/* If the session exists, this always succeeds */
 	par->status = ISCSI_STATUS_SUCCESS;
 
-	kill_session(session, ISCSI_STATUS_LOGOUT, LOGOUT_SESSION, FALSE);
+	kill_session(par->session_id,
+	    ISCSI_STATUS_LOGOUT, LOGOUT_SESSION,
+	    FALSE);
 }
 
 
@@ -1169,7 +1208,7 @@ logout(iscsi_logout_parameters_t *par)
  *          l        IN: The lwp pointer of the caller
  */
 
-static void
+static int
 add_connection(iscsi_login_parameters_t *par, struct lwp *l)
 {
 	session_t *session;
@@ -1181,12 +1220,15 @@ add_connection(iscsi_login_parameters_t 
 		mutex_exit(&iscsi_cleanup_mtx);
 		DEBOUT(("Session %d not found\n", par->session_id));
 		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
-		return;
+		return -1;
 	}
 	mutex_exit(&iscsi_cleanup_mtx);
-	if ((par->status = check_login_pars(par)) == 0) {
-		create_connection(par, session, l);
-	}
+
+	par->status = check_login_pars(par);
+	if (par->status)
+		return -1;
+
+	return create_connection(par, session, l);
 }
 
 
@@ -1255,7 +1297,6 @@ restore_connection(iscsi_login_parameter
 		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
 		return;
 	}
-
 	if ((conn = find_connection(sess, par->connection_id)) == NULL) {
 		mutex_exit(&iscsi_cleanup_mtx);
 		DEBOUT(("Connection %d not found in session %d\n",
@@ -1263,6 +1304,12 @@ restore_connection(iscsi_login_parameter
 		par->status = ISCSI_STATUS_INVALID_CONNECTION_ID;
 		return;
 	}
+	if (!conn->c_terminating) {
+		mutex_exit(&iscsi_cleanup_mtx);
+		DEBC(conn, 0, ("Connection is alive\n"));
+		par->status = ISCSI_STATUS_SUCCESS;
+		return;
+	}
 	mutex_exit(&iscsi_cleanup_mtx);
 
 	if ((par->status = check_login_pars(par)) == 0) {
@@ -1518,11 +1565,13 @@ kill_all_sessions(void)
 {
 	session_t *sess;
 	int rc = 0;
+	uint32_t sid;
 
 	mutex_enter(&iscsi_cleanup_mtx);
 	while ((sess = TAILQ_FIRST(&iscsi_sessions)) != NULL) {
+		sid = sess->s_id;
 		mutex_exit(&iscsi_cleanup_mtx);
-		kill_session(sess, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION,
+		kill_session(sid, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION,
 				FALSE);
 		mutex_enter(&iscsi_cleanup_mtx);
 	}
@@ -1548,7 +1597,6 @@ kill_all_sessions(void)
 void
 handle_connection_error(connection_t *conn, uint32_t status, int dologout)
 {
-
 	DEBC(conn, 0, ("*** Connection Error, status=%d, logout=%d, state=%d\n",
 				   status, dologout, conn->c_state));
 
@@ -1567,7 +1615,7 @@ handle_connection_error(connection_t *co
 void
 add_connection_cleanup(connection_t *conn)
 {
-	session_t *sess;
+	session_t *sess = NULL;
 
 	mutex_enter(&iscsi_cleanup_mtx);
 	if (conn->c_in_session) {
@@ -1622,7 +1670,7 @@ connection_timeout_stop(connection_t *co
 			kpause("connbusy", false, 1, &iscsi_cleanup_mtx);
 	}
 	mutex_exit(&iscsi_cleanup_mtx);
-}                        
+}
 
 void
 ccb_timeout_co(void *par)
@@ -1710,6 +1758,7 @@ iscsi_cleanup_thread(void *par)
 			callout_halt(&conn->c_timeout, NULL);
 			closef(conn->c_sock);
 			callout_destroy(&conn->c_timeout);
+			rw_destroy(&conn->c_sock_rw);
 			cv_destroy(&conn->c_idle_cv);
 			cv_destroy(&conn->c_ccb_cv);
 			cv_destroy(&conn->c_pdu_cv);

Index: src/sys/dev/iscsi/iscsi_main.c
diff -u src/sys/dev/iscsi/iscsi_main.c:1.40 src/sys/dev/iscsi/iscsi_main.c:1.41
--- src/sys/dev/iscsi/iscsi_main.c:1.40	Thu Apr 14 16:50:26 2022
+++ src/sys/dev/iscsi/iscsi_main.c	Tue Sep 13 13:09:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_main.c,v 1.40 2022/04/14 16:50:26 pgoyette Exp $	*/
+/*	$NetBSD: iscsi_main.c,v 1.41 2022/09/13 13:09:16 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -418,9 +418,10 @@ unmap_session(session_t *sess)
 	int rv = 1;
 
 	if ((dev = sess->s_child_dev) != NULL) {
-		sess->s_child_dev = NULL;
 		if (config_detach(dev, 0))
 			rv = 0;
+		if (rv)
+			sess->s_child_dev = NULL;
 	}
 
 	return rv;

Index: src/sys/dev/iscsi/iscsi_rcv.c
diff -u src/sys/dev/iscsi/iscsi_rcv.c:1.25 src/sys/dev/iscsi/iscsi_rcv.c:1.26
--- src/sys/dev/iscsi/iscsi_rcv.c:1.25	Sun Mar  4 07:37:43 2018
+++ src/sys/dev/iscsi/iscsi_rcv.c	Tue Sep 13 13:09:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_rcv.c,v 1.25 2018/03/04 07:37:43 mlelstv Exp $	*/
+/*	$NetBSD: iscsi_rcv.c,v 1.26 2022/09/13 13:09:16 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -51,7 +51,7 @@
 STATIC int
 my_soo_read(connection_t *conn, struct uio *u, int flags)
 {
-	struct socket *so = conn->c_sock->f_socket;
+	struct socket *so;
 	int ret;
 #ifdef ISCSI_DEBUG
 	size_t resid = u->uio_resid;
@@ -59,22 +59,34 @@ my_soo_read(connection_t *conn, struct u
 
 	DEBC(conn, 99, ("soo_read req: %zu\n", resid));
 
-	if (flags & MSG_WAITALL) {
-		flags &= ~MSG_WAITALL;
-		do {
-			int oresid = u->uio_resid;
-			ret = (*so->so_receive)(so, NULL, u, NULL, NULL, &flags);
-			if (!ret && u->uio_resid == oresid)
-				break;
-		} while (!ret && u->uio_resid > 0);
-	} else
-		ret = (*so->so_receive)(so, NULL, u, NULL, NULL, &flags);
+	rw_enter(&conn->c_sock_rw, RW_READER);
+	if (conn->c_sock == NULL) {
+		ret = EIO;
+	} else {
+		so = conn->c_sock->f_socket;
+		if (flags & MSG_WAITALL) {
+			flags &= ~MSG_WAITALL;
+			do {
+				int oresid = u->uio_resid;
+				ret = (*so->so_receive)(so, NULL, u,
+				   NULL, NULL, &flags);
+				if (!ret && u->uio_resid == oresid)
+					break;
+			} while (!ret && u->uio_resid > 0);
+		} else {
+			ret = (*so->so_receive)(so, NULL, u,
+			   NULL, NULL, &flags);
+		}
+	}
+
+	rw_exit(&conn->c_sock_rw);
 
 	if (ret || (flags != MSG_DONTWAIT && u->uio_resid)) {
 		DEBC(conn, 1, ("Read failed (ret: %d, req: %zu, out: %zu)\n",
 		               ret, resid, u->uio_resid));
-		handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR,
-		                        RECOVER_CONNECTION);
+		if (ret)
+			handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR,
+						RECOVER_CONNECTION);
 		return 1;
 	}
 	return 0;
@@ -810,34 +822,41 @@ receive_asynch_pdu(connection_t *conn, p
 	case 0:		   		/* SCSI Asynch event. Don't know what to do with it... */
 		break;
 
-	case 1:		   		/* Target requests logout. */
+	case 1:	 	/* Target requests logout. */
 		if (conn->c_session->s_active_connections > 1) {
 			kill_connection(conn, ISCSI_STATUS_TARGET_LOGOUT,
 						LOGOUT_CONNECTION, FALSE);
 		} else {
-			kill_session(conn->c_session, ISCSI_STATUS_TARGET_LOGOUT,
-						 LOGOUT_SESSION, FALSE);
+			kill_session(conn->c_session->s_id,
+				ISCSI_STATUS_TARGET_LOGOUT, LOGOUT_SESSION,
+				FALSE);
 		}
 		break;
 
-	case 2:				/* Target is dropping connection */
+	case 2:		/* Target is dropping connection */
 		conn = find_connection(conn->c_session,
-					ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter1));
+		    ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter1));
 		if (conn != NULL) {
-			conn->c_Time2Wait = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2);
-			conn->c_Time2Retain = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3);
+			conn->c_Time2Wait =
+			    ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2);
+			conn->c_Time2Retain =
+			    ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3);
 			kill_connection(conn, ISCSI_STATUS_TARGET_DROP,
 					NO_LOGOUT, TRUE);
 		}
 		break;
 
-	case 3:				/* Target is dropping all connections of session */
-		conn->c_session->s_DefaultTime2Wait = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2);
-		conn->c_session->s_DefaultTime2Retain = ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3);
-		kill_session(conn->c_session, ISCSI_STATUS_TARGET_DROP, NO_LOGOUT, TRUE);
+	case 3:		/* Target is dropping all connections of session */
+		conn->c_session->s_DefaultTime2Wait =
+		    ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter2);
+		conn->c_session->s_DefaultTime2Retain =
+		    ntohs(pdu->pdu_hdr.pduh_p.asynch.Parameter3);
+		kill_session(conn->c_session->s_id,
+			ISCSI_STATUS_TARGET_DROP, NO_LOGOUT,
+			TRUE);
 		break;
 
-	case 4:				/* Target requests parameter negotiation */
+	case 4:		/* Target requests parameter negotiation */
 		start_text_negotiation(conn);
 		break;
 
@@ -1144,12 +1163,12 @@ receive_pdu(connection_t *conn, pdu_t *p
 	MaxCmdSN = ntohl(pdu->pdu_hdr.pduh_p.nop_in.MaxCmdSN);
 
 	/* received a valid frame, reset timeout */
+	conn->c_num_timeouts = 0;
 	if ((pdu->pdu_hdr.pduh_Opcode & OPCODE_MASK) == TOP_NOP_In &&
 	    TAILQ_EMPTY(&conn->c_ccbs_waiting))
 		connection_timeout_start(conn, conn->c_idle_timeout_val);
 	else
 		connection_timeout_start(conn, CONNECTION_TIMEOUT);
-	conn->c_num_timeouts = 0;
 
 	/* Update session window */
 	mutex_enter(&sess->s_lock);

Index: src/sys/dev/iscsi/iscsi_send.c
diff -u src/sys/dev/iscsi/iscsi_send.c:1.38 src/sys/dev/iscsi/iscsi_send.c:1.39
--- src/sys/dev/iscsi/iscsi_send.c:1.38	Sun Jun  6 10:39:10 2021
+++ src/sys/dev/iscsi/iscsi_send.c	Tue Sep 13 13:09:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_send.c,v 1.38 2021/06/06 10:39:10 mlelstv Exp $	*/
+/*	$NetBSD: iscsi_send.c,v 1.39 2022/09/13 13:09:16 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc.
@@ -54,7 +54,7 @@
 STATIC int
 my_soo_write(connection_t *conn, struct uio *u)
 {
-	struct socket *so = conn->c_sock->f_socket;
+	struct socket *so;
 	int ret;
 #ifdef ISCSI_DEBUG
 	size_t resid = u->uio_resid;
@@ -62,7 +62,15 @@ my_soo_write(connection_t *conn, struct 
 
 	KASSERT(u->uio_resid != 0);
 
-	ret = (*so->so_send)(so, NULL, u, NULL, NULL, 0, conn->c_threadobj);
+	rw_enter(&conn->c_sock_rw, RW_READER);
+	if (conn->c_sock == NULL) {
+		ret = EIO;
+	} else {
+		so = conn->c_sock->f_socket;
+		ret = (*so->so_send)(so, NULL, u,
+		   NULL, NULL, 0, conn->c_threadobj);
+	}
+	rw_exit(&conn->c_sock_rw);
 
 	DEB(99, ("soo_write done: len = %zu\n", u->uio_resid));
 
@@ -140,6 +148,7 @@ reassign_tasks(connection_t *oldconn)
 	session_t *sess = oldconn->c_session;
 	connection_t *conn;
 	ccb_t *ccb;
+	ccb_list_t old_waiting;
 	pdu_t *pdu = NULL;
 	pdu_t *opdu;
 	int no_tm = 1;
@@ -154,6 +163,10 @@ reassign_tasks(connection_t *oldconn)
 		return;
 	}
 
+	TAILQ_INIT(&old_waiting);
+
+	mutex_enter(&oldconn->c_lock);
+
 	if (sess->s_ErrorRecoveryLevel >= 2) {
 		if (oldconn->c_loggedout == NOT_LOGGED_OUT) {
 			oldconn->c_loggedout = LOGOUT_SENT;
@@ -169,24 +182,34 @@ reassign_tasks(connection_t *oldconn)
 		if (!no_tm && oldconn->c_Time2Wait) {
 			DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n",
 						   oldconn->c_Time2Wait, hz));
-			kpause("Time2Wait", false, oldconn->c_Time2Wait * hz, NULL);
+			kpause("Time2Wait", false, oldconn->c_Time2Wait * hz, &oldconn->c_lock);
 		}
 	}
 
-	DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n",
-		sess->s_id, oldconn->c_id, conn->c_id, no_tm));
+	while ((ccb = TAILQ_FIRST(&oldconn->c_ccbs_waiting)) != NULL) {
+		suspend_ccb(ccb, FALSE);
+		TAILQ_INSERT_TAIL(&old_waiting, ccb, ccb_chain);
+	}
+
+	mutex_exit(&oldconn->c_lock);
 
+	DEBC(conn, 1, ("Reassign_tasks: S%dC%d -> S%dC%d, no_tm=%d, pdus old %d + new %d\n",
+		sess->s_id, oldconn->c_id, sess->s_id, conn->c_id, no_tm,
+		oldconn->c_pducount, conn->c_pducount));
 
 	/* XXX reassign waiting CCBs to new connection */
 
-	while ((ccb = TAILQ_FIRST(&oldconn->c_ccbs_waiting)) != NULL) {
+	while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
 		/* Copy PDU contents (PDUs are bound to connection) */
 		if ((pdu = get_pdu(conn, TRUE)) == NULL) {
+			DEBC(conn, 0, ("get_pdu failed, terminating=%d\n", conn->c_terminating));
+			/* new connection is terminating */
 			break;
 		}
 
+		TAILQ_REMOVE(&old_waiting, ccb, ccb_chain);
+
 		/* adjust CCB and clone PDU for new connection */
-		TAILQ_REMOVE(&oldconn->c_ccbs_waiting, ccb, ccb_chain);
 
 		opdu = ccb->ccb_pdu_waiting;
 		KASSERT((opdu->pdu_flags & PDUF_INQUEUE) == 0);
@@ -224,7 +247,7 @@ reassign_tasks(connection_t *oldconn)
 		atomic_inc_uint(&conn->c_usecount);
 
 		DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n",
-					   ccb, opdu, pdu));
+		   ccb, opdu, pdu));
 
 		/* kill temp pointer that is now referenced by the new PDU */
 		opdu->pdu_temp_data = NULL;
@@ -238,14 +261,24 @@ reassign_tasks(connection_t *oldconn)
 		mutex_exit(&conn->c_lock);
 	}
 
-	if (pdu == NULL) {
-		DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n"));
-		/* give up recovering, the other connection is screwed up as well... */
-		while ((ccb = TAILQ_FIRST(&oldconn->c_ccbs_waiting)) != NULL) {
+	if (TAILQ_FIRST(&old_waiting) != NULL) {
+		DEBC(conn, 0, ("Error while copying PDUs in reassign_tasks!\n"));
+		/*
+		 * give up recovering, the other connection is screwed up
+		 * as well...
+		 */
+
+		while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
+			TAILQ_REMOVE(&old_waiting, ccb, ccb_chain);
+
+			DEBC(oldconn, 1, ("Wake CCB %p for connection %d, terminating %d\n",
+			   ccb, ccb->ccb_connection->c_id, oldconn->c_terminating));
+			mutex_enter(&oldconn->c_lock);
+			suspend_ccb(ccb, TRUE);
+			mutex_exit(&oldconn->c_lock);
 			wake_ccb(ccb, oldconn->c_terminating);
 		}
-		/* XXX some CCBs might have been moved to new connection, but how is the
-		 * new connection handled or killed ? */
+
 		return;
 	}
 
@@ -262,7 +295,7 @@ reassign_tasks(connection_t *oldconn)
 
 				/* update CmdSN */
 				DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n",
-					   ccb->ccb_CmdSN, sn));
+				   ccb->ccb_CmdSN, sn));
 				ccb->ccb_CmdSN = sn;
 				pdu->pdu_hdr.pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN);
 			}
@@ -1637,10 +1670,10 @@ send_io_command(session_t *session, uint
 void
 connection_timeout(connection_t *conn)
 {
-
-	if (++conn->c_num_timeouts > MAX_CONN_TIMEOUTS)
+	if (++conn->c_num_timeouts > MAX_CONN_TIMEOUTS) {
+		DEBC(conn, 1, ("connection timeout %d\n", conn->c_num_timeouts));
 		handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT);
-	else {
+	} else {
 		if (conn->c_state == ST_FULL_FEATURE)
 			send_nop_out(conn, NULL);
 

Index: src/sys/dev/iscsi/iscsi_utils.c
diff -u src/sys/dev/iscsi/iscsi_utils.c:1.27 src/sys/dev/iscsi/iscsi_utils.c:1.28
--- src/sys/dev/iscsi/iscsi_utils.c:1.27	Sun Apr 21 11:45:08 2019
+++ src/sys/dev/iscsi/iscsi_utils.c	Tue Sep 13 13:09:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: iscsi_utils.c,v 1.27 2019/04/21 11:45:08 maya Exp $	*/
+/*	$NetBSD: iscsi_utils.c,v 1.28 2022/09/13 13:09:16 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
@@ -203,22 +203,28 @@ get_ccb(connection_t *conn, bool waitok)
 	session_t *sess = conn->c_session;
 
 	mutex_enter(&sess->s_lock);
-	do {
+	for (;;) {
 		ccb = TAILQ_FIRST(&sess->s_ccb_pool);
+
 		DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
 
 		if (ccb != NULL) {
 			TAILQ_REMOVE(&sess->s_ccb_pool, ccb, ccb_chain);
-		} else {
-			if (!waitok || conn->c_terminating) {
-				mutex_exit(&sess->s_lock);
-				return NULL;
-			}
-			cv_wait(&sess->s_ccb_cv, &sess->s_lock);
+			break;
 		}
-	} while (ccb == NULL);
+
+		if (!waitok)
+			break;
+
+		cv_wait(&sess->s_ccb_cv, &sess->s_lock);
+	}
 	mutex_exit(&sess->s_lock);
 
+	if (ccb == NULL) {
+		DEB(15, ("get_ccb: failed"));
+		return NULL;
+	}
+
 	ccb->ccb_flags = 0;
 	ccb->ccb_timedout = TOUT_NONE;
 	ccb->ccb_xs = NULL;
@@ -454,23 +460,27 @@ get_pdu(connection_t *conn, bool waitok)
 	pdu_t *pdu;
 
 	mutex_enter(&conn->c_lock);
-	do {
+	for (;;) {
 		pdu = TAILQ_FIRST(&conn->c_pdu_pool);
-		if (pdu != NULL)
-			TAILQ_REMOVE(&conn->c_pdu_pool, pdu, pdu_chain);
 
-		if (pdu == NULL) {
-			if (!waitok || conn->c_terminating) {
-				mutex_exit(&conn->c_lock);
-				DEB(15, ("get_pdu: failed"));
-				return NULL;
-			}
-			cv_wait(&conn->c_pdu_cv, &conn->c_lock);
+		if (pdu != NULL) {
+			TAILQ_REMOVE(&conn->c_pdu_pool, pdu, pdu_chain);
+			conn->c_pducount++;
+			break;
 		}
-	} while (pdu == NULL);
-	atomic_inc_uint(&conn->c_pducount);
+
+		if (!waitok)
+			break;
+
+		cv_wait(&conn->c_pdu_cv, &conn->c_lock);
+	}
 	mutex_exit(&conn->c_lock);
 
+	if (pdu == NULL) {
+		DEB(15, ("get_pdu: failed"));
+		return NULL;
+	}
+
 	memset(pdu, 0, sizeof(pdu_t));
 	pdu->pdu_connection = conn;
 	pdu->pdu_disp = PDUDISP_FREE;
@@ -497,8 +507,11 @@ free_pdu(pdu_t *pdu)
 
 	KASSERT((pdu->pdu_flags & PDUF_INQUEUE) == 0);
 
-	if (PDUDISP_UNUSED == (pdisp = pdu->pdu_disp))
+	if (PDUDISP_UNUSED == (pdisp = pdu->pdu_disp)) {
+		DEBC(conn, 0, ("freeing UNUSED pdu\n"));
 		return;
+	}
+
 	pdu->pdu_disp = PDUDISP_UNUSED;
 
 	/* free temporary data in this PDU */
@@ -506,7 +519,7 @@ free_pdu(pdu_t *pdu)
 		free(pdu->pdu_temp_data, M_TEMP);
 
 	mutex_enter(&conn->c_lock);
-	atomic_dec_uint(&conn->c_pducount);
+	conn->c_pducount--;
 	TAILQ_INSERT_TAIL(&conn->c_pdu_pool, pdu, pdu_chain);
 	cv_broadcast(&conn->c_pdu_cv);
 	mutex_exit(&conn->c_lock);

Reply via email to