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