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.
This commit is contained in:
mlelstv 2022-09-13 13:09:16 +00:00
parent f5d5f158d4
commit 1ec2b09a37
6 changed files with 237 additions and 118 deletions

View File

@ -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; /* Whether to encode parameters in hex or base64
#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 *);

View File

@ -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, uint32_t status, int logout, bool recover)
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, uint32_t status, int logout, bool recover)
}
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 status, int logout, bool recover)
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 status, int logout, bool recover)
/*
* 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_t *par, session_t *sess,
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_t *par, session_t *sess,
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_t *par, session_t *sess,
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_t *par, session_t *sess,
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_t *par, session_t *sess,
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_t *par, session_t *sess,
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_parameters_t *par, session_t *sess,
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_parameters_t *par, session_t *sess,
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, struct lwp *l, device_t dev)
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 *par, struct lwp *l)
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_parameters_t *par, struct lwp *l)
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_parameters_t *par, struct lwp *l)
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 *conn, uint32_t status, int dologout)
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 *conn)
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);

View File

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

View File

@ -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 uio *u, int flags)
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, pdu_t *pdu)
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 *pdu)
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);

View File

@ -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 uio *u)
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, uint64_t lun, scsireq_t *req,
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);

View File

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