[PATCH 1/3] libiscsi: fix nop xmit failure handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Mike Christie <michaelc@xxxxxxxxxxx>

If we cannot queue a nop, because we cannot allocate
resources then retry in recv timeout seconds.

Without this patch, last_ping does not get updated, so
we end up retrying right away.

Signed-off-by: Mike Christie <michaelc@xxxxxxxxxxx>
---
 drivers/scsi/libiscsi.c |   68 +++++++++++++++++++++++++++++++----------------
 1 files changed, 45 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 82c3fd4..5b4adc4 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -701,9 +701,10 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
 	struct iscsi_task *task;
 	itt_t itt;
+	int err;
 
 	if (session->state == ISCSI_STATE_TERMINATE)
-		return NULL;
+		return ERR_PTR(-ENOTCONN);
 
 	if (opcode == ISCSI_OP_LOGIN || opcode == ISCSI_OP_TEXT) {
 		/*
@@ -715,20 +716,20 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		if (conn->login_task->state != ISCSI_TASK_FREE) {
 			iscsi_conn_printk(KERN_ERR, conn, "Login/Text in "
 					  "progress. Cannot start new task.\n");
-			return NULL;
+			return ERR_PTR(-EBUSY);
 		}
 
 		task = conn->login_task;
 	} else {
 		if (session->state != ISCSI_STATE_LOGGED_IN)
-			return NULL;
+			return ERR_PTR(-ENOTCONN);
 
 		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
 		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
 		if (!kfifo_out(&session->cmdpool.queue,
 				 (void*)&task, sizeof(void*)))
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 	}
 	/*
 	 * released in complete pdu for task we expect a response for, and
@@ -748,7 +749,8 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		task->data_count = 0;
 
 	if (conn->session->tt->alloc_pdu) {
-		if (conn->session->tt->alloc_pdu(task, hdr->opcode)) {
+		err = conn->session->tt->alloc_pdu(task, hdr->opcode);
+		if (err) {
 			iscsi_conn_printk(KERN_ERR, conn, "Could not allocate "
 					 "pdu for mgmt task.\n");
 			goto free_task;
@@ -768,10 +770,12 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	}
 
 	if (!ihost->workq) {
-		if (iscsi_prep_mgmt_task(conn, task))
+		err = iscsi_prep_mgmt_task(conn, task);
+		if (err)
 			goto free_task;
 
-		if (session->tt->xmit_task(task))
+		err = session->tt->xmit_task(task);
+		if (err)
 			goto free_task;
 	} else {
 		list_add_tail(&task->running, &conn->mgmtqueue);
@@ -782,7 +786,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
 free_task:
 	__iscsi_put_task(task);
-	return NULL;
+	return ERR_PTR(err);
 }
 
 int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
@@ -790,13 +794,15 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
 {
 	struct iscsi_conn *conn = cls_conn->dd_data;
 	struct iscsi_session *session = conn->session;
-	int err = 0;
+	struct iscsi_task *task;
 
 	spin_lock_bh(&session->lock);
-	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
-		err = -EPERM;
+	task = __iscsi_conn_send_pdu(conn, hdr, data, data_size);
 	spin_unlock_bh(&session->lock);
-	return err;
+
+	if (IS_ERR(task))
+		return PTR_ERR(task);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
 
@@ -940,13 +946,14 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 	wake_up(&conn->ehwait);
 }
 
-static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
+static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
 {
         struct iscsi_nopout hdr;
 	struct iscsi_task *task;
+	int err;
 
 	if (!rhdr && conn->ping_task)
-		return;
+		return -EEXIST;
 
 	memset(&hdr, 0, sizeof(struct iscsi_nopout));
 	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
@@ -960,13 +967,19 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
 		hdr.ttt = RESERVED_ITT;
 
 	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
-	if (!task)
-		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
-	else if (!rhdr) {
+	if (IS_ERR(task)) {
+		err = PTR_ERR(task);
+
+		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout. "
+				  "Error %d.\n", err);
+		return err;
+	} else if (!rhdr) {
 		/* only track our nops */
 		conn->ping_task = task;
 		conn->last_ping = jiffies;
 	}
+
+	return 0;
 }
 
 static int iscsi_nop_out_rsp(struct iscsi_task *task,
@@ -1766,14 +1779,13 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
 	struct iscsi_session *session = conn->session;
 	struct iscsi_task *task;
 
-	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
-				      NULL, 0);
-	if (!task) {
+	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+	if (IS_ERR(task)) {
 		spin_unlock_bh(&session->lock);
 		iscsi_conn_printk(KERN_ERR, conn, "Could not send TMF.\n");
 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 		spin_lock_bh(&session->lock);
-		return -EPERM;
+		return PTR_ERR(task);
 	}
 	conn->tmfcmd_pdus_cnt++;
 	conn->tmf_timer.expires = timeout * HZ + jiffies;
@@ -2033,6 +2045,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
 	struct iscsi_conn *conn = (struct iscsi_conn *)data;
 	struct iscsi_session *session = conn->session;
 	unsigned long recv_timeout, next_timeout = 0, last_recv;
+	int err;
 
 	spin_lock(&session->lock);
 	if (session->state != ISCSI_STATE_LOGGED_IN)
@@ -2059,8 +2072,17 @@ static void iscsi_check_transport_timeouts(unsigned long data)
 	if (time_before_eq(last_recv + recv_timeout, jiffies)) {
 		/* send a ping to try to provoke some traffic */
 		ISCSI_DBG_CONN(conn, "Sending nopout as ping\n");
-		iscsi_send_nopout(conn, NULL);
-		next_timeout = conn->last_ping + (conn->ping_timeout * HZ);
+		err = iscsi_send_nopout(conn, NULL);
+		if (!err || err == -EEXIST)
+			next_timeout = conn->last_ping +
+						(conn->ping_timeout * HZ);
+		else
+			/*
+			 * If we could not send due to resource error or slow
+			 * conn not taking things off of queue quick enough
+			 * then we do not want to drop the session.
+			 */
+			next_timeout = jiffies + recv_timeout;
 	} else
 		next_timeout = last_recv + recv_timeout;
 
-- 
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux