From c0e509e7535372cd5d655bc5a20d3d2bae45df84 Mon Sep 17 00:00:00 2001
From: Mike Christie <michaelc@cs.wisc.edu>
Date: Wed, 7 May 2014 14:38:13 -0500
Subject: [PATCH] iscsid: retry login for ISCSI_ERR_HOST_NOT_FOUND
If a driver is being loaded then the scsi_host might not yet
be added. This has iscsid retry login if the host is not yet
in sysfs.
---
usr/initiator.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 100 insertions(+), 11 deletions(-)
diff --git a/usr/initiator.c b/usr/initiator.c
index 05a5b19..b4b8957 100644
--- a/usr/initiator.c
+++ b/usr/initiator.c
@@ -55,10 +55,19 @@
#define PROC_DIR "/proc"
+struct login_task_retry_info {
+ actor_t retry_actor;
+ queue_task_t *qtask;
+ node_rec_t *rec;
+ int retry_count;
+};
+
static void iscsi_login_timedout(void *data);
static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
struct iscsi_conn *conn, unsigned long tmo,
int event);
+static int queue_session_login_task_retry(struct login_task_retry_info *info,
+ node_rec_t *rec, queue_task_t *qtask);
static int iscsi_ev_context_alloc(iscsi_conn_t *conn)
{
@@ -324,14 +333,17 @@ session_release(iscsi_session_t *session)
}
static iscsi_session_t*
-__session_create(node_rec_t *rec, struct iscsi_transport *t)
+__session_create(node_rec_t *rec, struct iscsi_transport *t, int *rc)
{
iscsi_session_t *session;
- int hostno, rc = 0;
+ int hostno;
+
+ *rc = 0;
session = calloc(1, sizeof (*session));
if (session == NULL) {
log_debug(1, "can not allocate memory for session");
+ *rc = ISCSI_ERR_NOMEM;
return NULL;
}
log_debug(2, "Allocted session %p", session);
@@ -356,8 +368,8 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
session->initiator_name = dconfig->initiator_name;
else {
log_error("No initiator name set. Cannot create session.");
- free(session);
- return NULL;
+ *rc = ISCSI_ERR_INVAL;
+ goto free_session;
}
if (strlen(session->nrec.iface.alias))
@@ -386,8 +398,8 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
iscsi_session_init_params(session);
- hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, &rc);
- if (!rc) {
+ hostno = iscsi_sysfs_get_host_no_from_hwinfo(&rec->iface, rc);
+ if (!*rc) {
/*
* if the netdev or mac was set, then we are going to want
* to want to bind the all the conns/eps to a specific host
@@ -395,10 +407,18 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t)
*/
session->conn[0].bind_ep = 1;
session->hostno = hostno;
+ } else if (*rc == ISCSI_ERR_HOST_NOT_FOUND) {
+ goto free_session;
+ } else {
+ *rc = 0;
}
list_add_tail(&session->list, &t->sessions);
return session;
+
+free_session:
+ free(session);
+ return NULL;
}
static void iscsi_flush_context_pool(struct iscsi_session *session)
@@ -1862,8 +1882,7 @@ static int session_is_running(node_rec_t *rec)
return 0;
}
-int
-session_login_task(node_rec_t *rec, queue_task_t *qtask)
+static int __session_login_task(node_rec_t *rec, queue_task_t *qtask)
{
iscsi_session_t *session;
iscsi_conn_t *conn;
@@ -1930,8 +1949,10 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
rec->conn[0].iscsi.OFMarker = 0;
}
- session = __session_create(rec, t);
- if (!session)
+ session = __session_create(rec, t, &rc);
+ if (rc == ISCSI_ERR_HOST_NOT_FOUND)
+ return rc;
+ else if (!session)
return ISCSI_ERR_LOGIN;
/* FIXME: login all connections! marked as "automatic" */
@@ -1979,6 +2000,74 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask)
return ISCSI_SUCCESS;
}
+int
+session_login_task(node_rec_t *rec, queue_task_t *qtask)
+{
+ int rc;
+
+ rc = __session_login_task(rec, qtask);
+ if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
+ rc = queue_session_login_task_retry(NULL, rec, qtask);
+ if (rc)
+ return rc;
+ /*
+ * we are going to internally retry. Will return final rc
+ * when completed
+ */
+ return ISCSI_SUCCESS;
+ }
+ return rc;
+}
+
+static void session_login_task_retry(void *data)
+{
+ struct login_task_retry_info *info = data;
+ int rc;
+
+ rc = __session_login_task(info->rec, info->qtask);
+ if (rc == ISCSI_ERR_HOST_NOT_FOUND) {
+ if (info->retry_count == 5) {
+ /* give up */
+ goto write_rsp;
+ }
+
+ rc = queue_session_login_task_retry(info, info->rec,
+ info->qtask);
+ if (rc)
+ goto write_rsp;
+ /* we are going to internally retry */
+ return;
+ } else if (rc) {
+ /* hard error - no retry */
+ goto write_rsp;
+ } else
+ /* successfully started login operation */
+ goto free;
+write_rsp:
+ mgmt_ipc_write_rsp(info->qtask, rc);
+free:
+ free(info);
+}
+
+static int queue_session_login_task_retry(struct login_task_retry_info *info,
+ node_rec_t *rec, queue_task_t *qtask)
+{
+ if (!info) {
+ info = malloc(sizeof(*info));
+ if (!info)
+ return ISCSI_ERR_NOMEM;
+ memset(info, 0, sizeof(*info));
+ info->qtask = qtask;
+ info->rec = rec;
+ }
+
+ info->retry_count++;
+ log_debug(4, "queue session setup attempt in %d secs, retries %d\n",
+ 3, info->retry_count);
+ actor_timer(&info->retry_actor, 3000, session_login_task_retry, info);
+ return 0;
+}
+
static int
sync_conn(iscsi_session_t *session, uint32_t cid)
{
@@ -2006,7 +2095,7 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid)
if (!t)
return ISCSI_ERR_TRANS_NOT_FOUND;
- session = __session_create(rec, t);
+ session = __session_create(rec, t, &err);
if (!session)
return ISCSI_ERR_LOGIN;
--
1.9.3