Commit 3219e529 authored by Mike Christie's avatar Mike Christie Committed by James Bottomley

[SCSI] iscsi: fix writepsace race

We can race and misset the suspend bit if iscsi_write_space is
called then iscsi_send returns with a failure indicating
there is no space.

To handle this this patch returns a error upwards allowing xmitworker
to decide if we need to try and transmit again. For the no
write space case xmitworker will not retry, and instead
let iscsi_write_space queue it back up if needed (this relies
on the work queue code to properly requeue us if needed).
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 040515f5
This diff is collapsed.
......@@ -513,10 +513,11 @@ EXPORT_SYMBOL_GPL(iscsi_conn_failure);
static int iscsi_data_xmit(struct iscsi_conn *conn)
{
struct iscsi_transport *tt;
int rc = 0;
if (unlikely(conn->suspend_tx)) {
debug_scsi("conn %d Tx suspended!\n", conn->id);
return 0;
return -ENODATA;
}
tt = conn->session->tt;
......@@ -536,13 +537,15 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
BUG_ON(conn->ctask && conn->mtask);
if (conn->ctask) {
if (tt->xmit_cmd_task(conn, conn->ctask))
rc = tt->xmit_cmd_task(conn, conn->ctask);
if (rc)
goto again;
/* done with this in-progress ctask */
conn->ctask = NULL;
}
if (conn->mtask) {
if (tt->xmit_mgmt_task(conn, conn->mtask))
rc = tt->xmit_mgmt_task(conn, conn->mtask);
if (rc)
goto again;
/* done with this in-progress mtask */
conn->mtask = NULL;
......@@ -556,7 +559,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock);
if (tt->xmit_mgmt_task(conn, conn->mtask))
rc = tt->xmit_mgmt_task(conn, conn->mtask);
if (rc)
goto again;
}
/* done with this mtask */
......@@ -574,7 +578,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
if (list_empty(&conn->ctask->running))
list_add_tail(&conn->ctask->running, &conn->run_list);
spin_unlock_bh(&conn->session->lock);
if (tt->xmit_cmd_task(conn, conn->ctask))
rc = tt->xmit_cmd_task(conn, conn->ctask);
if (rc)
goto again;
}
/* done with this ctask */
......@@ -588,32 +593,34 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock);
if (tt->xmit_mgmt_task(conn, conn->mtask))
rc = tt->xmit_mgmt_task(conn, conn->mtask);
if (rc)
goto again;
}
/* done with this mtask */
conn->mtask = NULL;
}
return 0;
return -ENODATA;
again:
if (unlikely(conn->suspend_tx))
return 0;
return -ENODATA;
return -EAGAIN;
return rc;
}
static void iscsi_xmitworker(void *data)
{
struct iscsi_conn *conn = data;
int rc;
/*
* serialize Xmit worker on a per-connection basis.
*/
mutex_lock(&conn->xmitmutex);
if (iscsi_data_xmit(conn))
scsi_queue_work(conn->session->host, &conn->xmitwork);
do {
rc = iscsi_data_xmit(conn);
} while (rc >= 0 || rc == -EAGAIN);
mutex_unlock(&conn->xmitmutex);
}
......
......@@ -57,8 +57,12 @@ struct iscsi_mgmt_task;
* Called from queuecommand with session lock held.
* @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs.
* Called from iscsi_conn_send_generic with xmitmutex.
* @xmit_cmd_task: requests LLD to transfer cmd task
* @xmit_mgmt_task: requests LLD to transfer mgmt task
* @xmit_cmd_task: Requests LLD to transfer cmd task. Returns 0 or the
* the number of bytes transferred on success, and -Exyz
* value on error.
* @xmit_mgmt_task: Requests LLD to transfer mgmt task. Returns 0 or the
* the number of bytes transferred on success, and -Exyz
* value on error.
* @cleanup_cmd_task: requests LLD to fail cmd task. Called with xmitmutex
* and session->lock after the connection has been
* suspended and terminated during recovery. If called
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment