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:
parent
f5d5f158d4
commit
1ec2b09a37
|
@ -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 *);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue