diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2007-08-13 13:42:17 -0500 |
---|---|---|
committer | Mike Christie <michaelc@cs.wisc.edu> | 2007-08-13 13:42:17 -0500 |
commit | 681c66f6bec199a6248e48c8e9ba40350fca3ff9 (patch) | |
tree | b94fd89dd8e2298fe8bb9975184d4b03c3603d75 | |
parent | 9ec75c98b00f6d6a33cfc74b86605b5a91753034 (diff) | |
download | open-iscsi-681c66f6bec199a6248e48c8e9ba40350fca3ff9.tar.gz |
fix DefaultTime2Wait handling and fix libiscsi null ptr ref.
We were not using the DefaultTime2Wait value we negotiated for.
We could hit a null ptr in libiscsi if we called stop and the
connection had not been setup.
-rw-r--r-- | include/iscsi_proto.h | 2 | ||||
-rw-r--r-- | kernel/libiscsi.c | 8 | ||||
-rw-r--r-- | usr/initiator.c | 164 | ||||
-rw-r--r-- | usr/initiator.h | 1 | ||||
-rw-r--r-- | usr/util.c | 2 |
5 files changed, 83 insertions, 94 deletions
diff --git a/include/iscsi_proto.h b/include/iscsi_proto.h index 059fd74..e821932 100644 --- a/include/iscsi_proto.h +++ b/include/iscsi_proto.h @@ -615,6 +615,8 @@ struct iscsi_reject { #define ISCSI_MIN_MAX_BURST_LEN 512 #define ISCSI_MAX_MAX_BURST_LEN 16777215 +#define ISCSI_DEF_TIME2WAIT 2 + /************************* RFC 3720 End *****************************/ #endif /* ISCSI_PROTO_H */ diff --git a/kernel/libiscsi.c b/kernel/libiscsi.c index e7dbfb1..01e31e7 100644 --- a/kernel/libiscsi.c +++ b/kernel/libiscsi.c @@ -1742,6 +1742,14 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, } /* + * The LLD either freed/unset the lock on us, or userspace called + * stop but did not create a proper connection (connection was never + * bound or it was unbound then stop was called). + */ + if (!conn->recv_lock) + return; + + /* * When this is called for the in_login state, we only want to clean * up the login task and connection. We do not need to block and set * the recovery state again diff --git a/usr/initiator.c b/usr/initiator.c index 01d0eb6..4e9953b 100644 --- a/usr/initiator.c +++ b/usr/initiator.c @@ -40,8 +40,6 @@ static void iscsi_login_timedout(void *data); -#define DEFAULT_TIME2WAIT 2 - /* * calculate parameter's padding */ @@ -336,6 +334,63 @@ setup_portal(iscsi_conn_t *conn, conn_rec_t *conn_rec) return 0; } +static void +iscsi_copy_operational_params(iscsi_conn_t *conn) +{ + iscsi_session_t *session = conn->session; + conn_rec_t *conn_rec = &session->nrec.conn[conn->id]; + node_rec_t *rec = &session->nrec; + + /* + * iSCSI default, unless declared otherwise by the + * target during login + */ + conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; + conn->hdrdgst_en = conn_rec->iscsi.HeaderDigest; + conn->datadgst_en = conn_rec->iscsi.DataDigest; + + conn->max_recv_dlength = + __padding(conn_rec->iscsi.MaxRecvDataSegmentLength); + if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN || + conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) { + log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be " + "within %u and %u. Setting to %u\n", + ISCSI_MIN_MAX_RECV_SEG_LEN, + ISCSI_MAX_MAX_RECV_SEG_LEN, + DEF_INI_MAX_RECV_SEG_LEN); + conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN; + } + + /* session's operational parameters */ + session->initial_r2t_en = rec->session.iscsi.InitialR2T; + session->imm_data_en = rec->session.iscsi.ImmediateData; + session->first_burst = __padding(rec->session.iscsi.FirstBurstLength); + if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN || + session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) { + log_error("Invalid iscsi.FirstBurstLength of %u. Must be " + "within %u and %u. Setting to %u\n", + session->first_burst, + ISCSI_MIN_FIRST_BURST_LEN, + ISCSI_MAX_FIRST_BURST_LEN, + DEF_INI_FIRST_BURST_LEN); + session->first_burst = DEF_INI_FIRST_BURST_LEN; + } + + session->max_burst = __padding(rec->session.iscsi.MaxBurstLength); + if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN || + session->max_burst > ISCSI_MAX_MAX_BURST_LEN) { + log_error("Invalid iscsi.MaxBurstLength of %u. Must be " + "within %u and %u. Setting to %u\n", + session->max_burst, ISCSI_MIN_MAX_BURST_LEN, + ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN); + session->max_burst = DEF_INI_MAX_BURST_LEN; + } + + session->def_time2wait = rec->session.iscsi.DefaultTime2Wait; + session->def_time2retain = rec->session.iscsi.DefaultTime2Retain; + session->erl = rec->session.iscsi.ERL; +} + static int __session_conn_create(iscsi_session_t *session, int cid) { @@ -348,6 +403,8 @@ __session_conn_create(iscsi_session_t *session, int cid) return ENOMEM; } + conn->state = STATE_FREE; + conn->session = session; conn->socket_fd = -1; /* connection's timeouts */ conn->id = cid; @@ -393,26 +450,7 @@ __session_conn_create(iscsi_session_t *session, int cid) conn->idle_timeout = conn_rec->timeo.idle_timeout; conn->ping_timeout = conn_rec->timeo.ping_timeout; - /* operational parameters */ - conn->max_recv_dlength = - __padding(conn_rec->iscsi.MaxRecvDataSegmentLength); - if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN || - conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) { - log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be " - "within %u and %u. Setting to %u\n", - ISCSI_MIN_MAX_RECV_SEG_LEN, - ISCSI_MAX_MAX_RECV_SEG_LEN, - DEF_INI_MAX_RECV_SEG_LEN); - conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN; - } - - /* - * iSCSI default, unless declared otherwise by the - * target during login - */ - conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; - conn->hdrdgst_en = conn_rec->iscsi.HeaderDigest; - conn->datadgst_en = conn_rec->iscsi.DataDigest; + iscsi_copy_operational_params(conn); /* TCP options */ conn->tcp_window_size = conn_rec->tcp.window_size; @@ -422,10 +460,6 @@ __session_conn_create(iscsi_session_t *session, int cid) err = setup_portal(conn, conn_rec); if (err) return err; - - conn->state = STATE_FREE; - conn->session = session; - return 0; } @@ -461,34 +495,6 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) /* save node record. we might need it for redirection */ memcpy(&session->nrec, rec, sizeof(node_rec_t)); - /* session's operational parameters */ - session->initial_r2t_en = rec->session.iscsi.InitialR2T; - session->imm_data_en = rec->session.iscsi.ImmediateData; - session->first_burst = __padding(rec->session.iscsi.FirstBurstLength); - if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN || - session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) { - log_error("Invalid iscsi.FirstBurstLength of %u. Must be " - "within %u and %u. Setting to %u\n", - session->first_burst, - ISCSI_MIN_FIRST_BURST_LEN, - ISCSI_MAX_FIRST_BURST_LEN, - DEF_INI_FIRST_BURST_LEN); - session->first_burst = DEF_INI_FIRST_BURST_LEN; - } - - session->max_burst = __padding(rec->session.iscsi.MaxBurstLength); - if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN || - session->max_burst > ISCSI_MAX_MAX_BURST_LEN) { - log_error("Invalid iscsi.MaxBurstLength of %u. Must be " - "within %u and %u. Setting to %u\n", - session->max_burst, ISCSI_MIN_MAX_BURST_LEN, - ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN); - session->max_burst = DEF_INI_MAX_BURST_LEN; - } - - session->def_time2wait = rec->session.iscsi.DefaultTime2Wait; - session->def_time2retain = rec->session.iscsi.DefaultTime2Retain; - session->erl = rec->session.iscsi.ERL; session->portal_group_tag = rec->tpgt; session->type = ISCSI_SESSION_TYPE_NORMAL; session->r_stage = R_STAGE_NO_CHANGE; @@ -628,34 +634,6 @@ session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask, } static void -reset_iscsi_params(iscsi_conn_t *conn) -{ - iscsi_session_t *session = conn->session; - conn_rec_t *conn_rec = &session->nrec.conn[conn->id]; - node_rec_t *rec = &session->nrec; - - /* operational parameters */ - conn->max_recv_dlength = - __padding(conn_rec->iscsi.MaxRecvDataSegmentLength); - /* - * iSCSI default, unless declared otherwise by the - * target during login - */ - conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; - conn->hdrdgst_en = conn_rec->iscsi.HeaderDigest; - conn->datadgst_en = conn_rec->iscsi.DataDigest; - - /* session's operational parameters */ - session->initial_r2t_en = rec->session.iscsi.InitialR2T; - session->imm_data_en = rec->session.iscsi.ImmediateData; - session->first_burst = __padding(rec->session.iscsi.FirstBurstLength); - session->max_burst = __padding(rec->session.iscsi.MaxBurstLength); - session->def_time2wait = rec->session.iscsi.DefaultTime2Wait; - session->def_time2retain = rec->session.iscsi.DefaultTime2Retain; - session->erl = rec->session.iscsi.ERL; -} - -static void queue_delayed_reopen(queue_task_t *qtask, int delay) { iscsi_conn_t *conn = qtask->conn; @@ -674,14 +652,14 @@ queue_delayed_reopen(queue_task_t *qtask, int delay) static void __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) { - int rc, delay; iscsi_session_t *session = conn->session; struct iscsi_conn_context *conn_context; + uint32_t delay; + int rc; log_debug(1, "re-opening session %d (reopen_cnt %d)", session->id, session->reopen_cnt); - reset_iscsi_params(conn); qtask->conn = conn; /* flush stale polls or errors queued */ @@ -695,6 +673,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) conn->id, do_stop)) { log_error("can't stop connection %d:%d (%d)", session->id, conn->id, errno); + delay = 5; goto queue_reopen; } log_debug(3, "connection %d:%d is stopped for recovery", @@ -702,7 +681,9 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) } conn->session->t->template->ep_disconnect(conn); - if (session->time2wait) + delay = session->def_time2wait; + session->def_time2wait = 0; + if (delay) goto queue_reopen; conn_context = iscsi_conn_context_get(conn, 0); @@ -710,6 +691,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) /* while reopening the recv pool should be full */ log_error("BUG: __session_conn_reopen could not get conn " "context for recv."); + delay = 2; goto queue_reopen; } conn_context->data = qtask; @@ -725,6 +707,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) log_error("cannot make a connection to %s:%s (%d)", conn->host, serv, errno); + delay = 3; iscsi_conn_context_put(conn_context); goto queue_reopen; } @@ -737,11 +720,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) return; queue_reopen: - if (session->time2wait) - delay = session->time2wait; - else - delay = DEFAULT_TIME2WAIT; - session->time2wait = 0; + log_debug(4, "Waiting %u seconds before trying to reconnect.\n", delay); queue_delayed_reopen(qtask, delay); } @@ -1480,14 +1459,14 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) log_warning("Target dropping connection %u, reconnect min %u " "max %u\n", ntohs(async_hdr->param1), ntohs(async_hdr->param2), ntohs(async_hdr->param3)); - session->time2wait = + session->def_time2wait = (uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL; break; case ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS: log_warning("Target dropping all connections, reconnect min %u " "max %u\n", ntohs(async_hdr->param2), ntohs(async_hdr->param3)); - session->time2wait = + session->def_time2wait = (uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL; break; case ISCSI_ASYNC_MSG_PARAM_NEGOTIATION: @@ -1636,6 +1615,7 @@ static void session_conn_poll(void *data) "%d:%d", session->id, conn->id); } + iscsi_copy_operational_params(conn); /* * TODO: use the iface number or some other value * so this will be persistent diff --git a/usr/initiator.h b/usr/initiator.h index 489433c..5a8d388 100644 --- a/usr/initiator.h +++ b/usr/initiator.h @@ -196,7 +196,6 @@ typedef struct iscsi_session { uint32_t max_burst; uint32_t pdu_inorder_en; uint32_t dataseq_inorder_en; - uint32_t time2wait; uint32_t def_time2wait; uint32_t def_time2retain; int type; @@ -197,7 +197,7 @@ void idbm_node_setup_defaults(node_rec_t *rec) rec->session.iscsi.ImmediateData = 1; rec->session.iscsi.FirstBurstLength = DEF_INI_FIRST_BURST_LEN; rec->session.iscsi.MaxBurstLength = DEF_INI_MAX_BURST_LEN; - rec->session.iscsi.DefaultTime2Wait = 0; + rec->session.iscsi.DefaultTime2Wait = ISCSI_DEF_TIME2WAIT; rec->session.iscsi.DefaultTime2Retain = 0; rec->session.iscsi.MaxConnections = 1; rec->session.iscsi.MaxOutstandingR2T = 1; |