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); ...@@ -513,10 +513,11 @@ EXPORT_SYMBOL_GPL(iscsi_conn_failure);
static int iscsi_data_xmit(struct iscsi_conn *conn) static int iscsi_data_xmit(struct iscsi_conn *conn)
{ {
struct iscsi_transport *tt; struct iscsi_transport *tt;
int rc = 0;
if (unlikely(conn->suspend_tx)) { if (unlikely(conn->suspend_tx)) {
debug_scsi("conn %d Tx suspended!\n", conn->id); debug_scsi("conn %d Tx suspended!\n", conn->id);
return 0; return -ENODATA;
} }
tt = conn->session->tt; tt = conn->session->tt;
...@@ -536,13 +537,15 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) ...@@ -536,13 +537,15 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
BUG_ON(conn->ctask && conn->mtask); BUG_ON(conn->ctask && conn->mtask);
if (conn->ctask) { if (conn->ctask) {
if (tt->xmit_cmd_task(conn, conn->ctask)) rc = tt->xmit_cmd_task(conn, conn->ctask);
if (rc)
goto again; goto again;
/* done with this in-progress ctask */ /* done with this in-progress ctask */
conn->ctask = NULL; conn->ctask = NULL;
} }
if (conn->mtask) { if (conn->mtask) {
if (tt->xmit_mgmt_task(conn, conn->mtask)) rc = tt->xmit_mgmt_task(conn, conn->mtask);
if (rc)
goto again; goto again;
/* done with this in-progress mtask */ /* done with this in-progress mtask */
conn->mtask = NULL; conn->mtask = NULL;
...@@ -556,7 +559,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) ...@@ -556,7 +559,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running, list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list); &conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock); 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; goto again;
} }
/* done with this mtask */ /* done with this mtask */
...@@ -574,7 +578,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) ...@@ -574,7 +578,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
if (list_empty(&conn->ctask->running)) if (list_empty(&conn->ctask->running))
list_add_tail(&conn->ctask->running, &conn->run_list); list_add_tail(&conn->ctask->running, &conn->run_list);
spin_unlock_bh(&conn->session->lock); 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; goto again;
} }
/* done with this ctask */ /* done with this ctask */
...@@ -588,32 +593,34 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) ...@@ -588,32 +593,34 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running, list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list); &conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock); 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; goto again;
} }
/* done with this mtask */ /* done with this mtask */
conn->mtask = NULL; conn->mtask = NULL;
} }
return 0; return -ENODATA;
again: again:
if (unlikely(conn->suspend_tx)) if (unlikely(conn->suspend_tx))
return 0; return -ENODATA;
return -EAGAIN; return rc;
} }
static void iscsi_xmitworker(void *data) static void iscsi_xmitworker(void *data)
{ {
struct iscsi_conn *conn = data; struct iscsi_conn *conn = data;
int rc;
/* /*
* serialize Xmit worker on a per-connection basis. * serialize Xmit worker on a per-connection basis.
*/ */
mutex_lock(&conn->xmitmutex); mutex_lock(&conn->xmitmutex);
if (iscsi_data_xmit(conn)) do {
scsi_queue_work(conn->session->host, &conn->xmitwork); rc = iscsi_data_xmit(conn);
} while (rc >= 0 || rc == -EAGAIN);
mutex_unlock(&conn->xmitmutex); mutex_unlock(&conn->xmitmutex);
} }
......
...@@ -57,8 +57,12 @@ struct iscsi_mgmt_task; ...@@ -57,8 +57,12 @@ struct iscsi_mgmt_task;
* Called from queuecommand with session lock held. * Called from queuecommand with session lock held.
* @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs. * @init_mgmt_task: Initialize a iscsi_mgmt_task and any internal structs.
* Called from iscsi_conn_send_generic with xmitmutex. * Called from iscsi_conn_send_generic with xmitmutex.
* @xmit_cmd_task: requests LLD to transfer cmd task * @xmit_cmd_task: Requests LLD to transfer cmd task. Returns 0 or the
* @xmit_mgmt_task: requests LLD to transfer mgmt task * 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 * @cleanup_cmd_task: requests LLD to fail cmd task. Called with xmitmutex
* and session->lock after the connection has been * and session->lock after the connection has been
* suspended and terminated during recovery. If called * 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