lib/iscsi: Request logout to asynchronously to initiator

Request logout to the initiator asynchronously when exiting the
running connection from the target.

Based on this patch, the next patch will make flushing PDUs possible
only when the connection is RUNNING (or INVALID) and remove the
tight loop in iscsi_conn_flush_pdus().

Set timeout of logout request as 30 seconds. 30 seconds is as same as
NOP timeout and will be reasonable for now.

Add and use logout_request_timer to check the timeout.

When the connection gets internal a logout request, move the connection
to EXITING state if the connection is in INVALID state, request logout
to initiator and start 30 seconds timer if the connection is in RUNNING
state and logout is not requested yet, or do nothing otherwise.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I43192be9fd7112ad444152c0dd88f99a14aa8d30
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/470705
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-10-08 09:30:42 +09:00 committed by Changpeng Liu
parent 7814351539
commit fe5611b79b
5 changed files with 73 additions and 11 deletions

View File

@ -287,6 +287,7 @@ spdk_iscsi_conn_construct(struct spdk_iscsi_portal *portal,
SPDK_ERRLOG("iscsi_conn_params_init() failed\n");
goto error_return;
}
conn->logout_request_timer = NULL;
conn->logout_timer = NULL;
conn->shutdown_timer = NULL;
SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "Launching connection on acceptor thread\n");
@ -639,6 +640,7 @@ _iscsi_conn_destruct(struct spdk_iscsi_conn *conn)
iscsi_poll_group_remove_conn(conn->pg, conn);
spdk_sock_close(&conn->sock);
spdk_poller_unregister(&conn->logout_request_timer);
spdk_poller_unregister(&conn->logout_timer);
rc = iscsi_conn_free_tasks(conn);
@ -731,8 +733,63 @@ iscsi_conn_check_shutdown(void *arg)
return 1;
}
static void
iscsi_send_logout_request(struct spdk_iscsi_conn *conn)
{
struct spdk_iscsi_pdu *rsp_pdu;
struct iscsi_bhs_async *rsph;
rsp_pdu = spdk_get_pdu();
assert(rsp_pdu != NULL);
rsph = (struct iscsi_bhs_async *)&rsp_pdu->bhs;
rsp_pdu->data = NULL;
rsph->opcode = ISCSI_OP_ASYNC;
to_be32(&rsph->ffffffff, 0xFFFFFFFF);
rsph->async_event = 1;
to_be16(&rsph->param3, ISCSI_LOGOUT_REQUEST_TIMEOUT);
to_be32(&rsph->stat_sn, conn->StatSN);
to_be32(&rsph->exp_cmd_sn, conn->sess->ExpCmdSN);
to_be32(&rsph->max_cmd_sn, conn->sess->MaxCmdSN);
spdk_iscsi_conn_write_pdu(conn, rsp_pdu);
}
static int
logout_request_timeout(void *arg)
{
struct spdk_iscsi_conn *conn = arg;
if (conn->state < ISCSI_CONN_STATE_EXITING) {
conn->state = ISCSI_CONN_STATE_EXITING;
}
return -1;
}
static void
iscsi_conn_request_logout(struct spdk_iscsi_conn *conn)
{
if (conn->state == ISCSI_CONN_STATE_INVALID) {
/* Move it to EXITING state if the connection is in login. */
conn->state = ISCSI_CONN_STATE_EXITING;
} else if (conn->state == ISCSI_CONN_STATE_RUNNING &&
conn->logout_request_timer == NULL) {
/* If the connection is running and logout is not requested yet,
* request logout to initiator and wait for the logout process
* to start.
*/
iscsi_send_logout_request(conn);
conn->logout_request_timer = spdk_poller_register(logout_request_timeout,
conn, ISCSI_LOGOUT_REQUEST_TIMEOUT * 1000000);
}
}
void
spdk_iscsi_conns_start_exit(struct spdk_iscsi_tgt_node *target)
spdk_iscsi_conns_request_logout(struct spdk_iscsi_tgt_node *target)
{
struct spdk_iscsi_conn *conn;
int i;
@ -749,12 +806,7 @@ spdk_iscsi_conns_start_exit(struct spdk_iscsi_tgt_node *target)
continue;
}
/* Do not set conn->state if the connection has already started exiting.
* This ensures we do not move a connection from EXITED state back to EXITING.
*/
if (conn->state < ISCSI_CONN_STATE_EXITING) {
conn->state = ISCSI_CONN_STATE_EXITING;
}
iscsi_conn_request_logout(conn);
}
pthread_mutex_unlock(&g_conns_mutex);
@ -763,7 +815,7 @@ spdk_iscsi_conns_start_exit(struct spdk_iscsi_tgt_node *target)
void
spdk_shutdown_iscsi_conns(void)
{
spdk_iscsi_conns_start_exit(NULL);
spdk_iscsi_conns_request_logout(NULL);
g_shutdown_timer = spdk_poller_register(iscsi_conn_check_shutdown, NULL, 1000);
}

View File

@ -94,6 +94,11 @@ struct spdk_iscsi_conn {
uint64_t last_fill;
uint64_t last_nopin;
/* Timer used to destroy connection after requesting logout if
* initiator does not send logout request.
*/
struct spdk_poller *logout_request_timer;
/* Timer used to destroy connection after logout if initiator does
* not close the connection.
*/
@ -174,7 +179,7 @@ extern struct spdk_iscsi_conn *g_conns_array;
int spdk_initialize_iscsi_conns(void);
void spdk_shutdown_iscsi_conns(void);
void spdk_iscsi_conns_start_exit(struct spdk_iscsi_tgt_node *target);
void spdk_iscsi_conns_request_logout(struct spdk_iscsi_tgt_node *target);
int spdk_iscsi_get_active_conns(struct spdk_iscsi_tgt_node *target);
int spdk_iscsi_conn_construct(struct spdk_iscsi_portal *portal, struct spdk_sock *sock);

View File

@ -122,6 +122,11 @@
*/
#define DEFAULT_MAX_QUEUE_DEPTH 64
/** Defines how long we should wait for a logout request when the target
* requests logout to the initiator asynchronously.
*/
#define ISCSI_LOGOUT_REQUEST_TIMEOUT 30 /* in seconds */
/** Defines how long we should wait for a TCP close after responding to a
* logout request, before terminating the connection ourselves.
*/

View File

@ -689,7 +689,7 @@ iscsi_tgt_node_destruct(struct spdk_iscsi_tgt_node *target,
target->destruct_cb_fn = cb_fn;
target->destruct_cb_arg = cb_arg;
spdk_iscsi_conns_start_exit(target);
spdk_iscsi_conns_request_logout(target);
if (spdk_iscsi_get_active_conns(target) != 0) {
target->destruct_poller = spdk_poller_register(iscsi_tgt_node_check_active_conns,

View File

@ -119,7 +119,7 @@ DEFINE_STUB(spdk_scsi_dev_delete_port, int,
DEFINE_STUB_V(spdk_shutdown_iscsi_conns, (void));
DEFINE_STUB_V(spdk_iscsi_conns_start_exit, (struct spdk_iscsi_tgt_node *target));
DEFINE_STUB_V(spdk_iscsi_conns_request_logout, (struct spdk_iscsi_tgt_node *target));
DEFINE_STUB(spdk_iscsi_get_active_conns, int, (struct spdk_iscsi_tgt_node *target), 0);