@@ -422,7 +422,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
if (session->tt->init_task && session->tt->init_task(task))
return -EIO;
+ spin_lock_bh(&task->lock);
task->state = ISCSI_TASK_RUNNING;
+ spin_unlock_bh(&task->lock);
+
session->cmdsn++;
conn->scsicmd_pdus_cnt++;
@@ -440,7 +443,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
* __iscsi_free_task - free a task
* @task: iscsi cmd task
*
- * Must be called with session back_lock.
* This function returns the scsi command to scsi-ml or cleans
* up mgmt tasks then returns the task to the pool.
*/
@@ -481,8 +483,6 @@ static void iscsi_free_task(struct iscsi_task *task)
if (!sc)
return;
- /* SCSI eh reuses commands to verify us */
- sc->SCp.ptr = NULL;
sc->scsi_done(sc);
}
@@ -514,8 +514,6 @@ EXPORT_SYMBOL_GPL(iscsi_put_task);
* iscsi_finish_task - finish a task
* @task: iscsi cmd task
* @state: state to complete task with
- *
- * Must be called with session back_lock.
*/
static void iscsi_finish_task(struct iscsi_task *task, int state)
{
@@ -524,11 +522,15 @@ static void iscsi_finish_task(struct iscsi_task *task, int state)
ISCSI_DBG_SESSION(conn->session,
"complete task itt 0x%x state %d sc %p\n",
task->itt, task->state, task->sc);
- if (task->state == ISCSI_TASK_COMPLETED ||
- task->state == ISCSI_TASK_ABRT_TMF)
+ spin_lock_bh(&task->lock);
+ if (iscsi_task_is_completed(task)) {
+ spin_unlock_bh(&task->lock);
return;
+ }
+
WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
task->state = state;
+ spin_unlock_bh(&task->lock);
if (READ_ONCE(conn->ping_task) == task)
WRITE_ONCE(conn->ping_task, NULL);
@@ -562,7 +564,7 @@ void iscsi_complete_scsi_task(struct iscsi_task *task,
EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
/*
- * Must be called with back and frwd lock
+ * Must be called with the task and frwd lock
*/
static bool cleanup_queued_task(struct iscsi_task *task)
{
@@ -606,9 +608,9 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
struct scsi_cmnd *sc;
int state;
- spin_lock_bh(&conn->session->back_lock);
+ spin_lock_bh(&task->lock);
if (cleanup_queued_task(task)) {
- spin_unlock_bh(&conn->session->back_lock);
+ spin_unlock_bh(&task->lock);
return;
}
@@ -628,8 +630,9 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
sc = task->sc;
sc->result = err << 16;
scsi_set_resid(sc, scsi_bufflen(sc));
+ spin_unlock_bh(&task->lock);
+
iscsi_finish_task(task, state);
- spin_unlock_bh(&conn->session->back_lock);
}
static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -1726,7 +1729,6 @@ static struct iscsi_task *iscsi_init_scsi_task(struct iscsi_conn *conn,
struct iscsi_task *task = scsi_cmd_priv(sc);
sc->SCp.phase = conn->session->age;
- sc->SCp.ptr = (char *) task;
refcount_set(&task->refcount, 1);
task->itt = blk_mq_unique_tag(sc->request);
@@ -1769,7 +1771,6 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
int sess_state;
sc->result = 0;
- sc->SCp.ptr = NULL;
ihost = shost_priv(host);
@@ -1877,9 +1878,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
prepd_reject:
spin_unlock_bh(&session->frwd_lock);
- spin_lock_bh(&session->back_lock);
__iscsi_free_task(task);
- spin_unlock_bh(&session->back_lock);
reject:
ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
sc->cmnd[0], reason);
@@ -1888,9 +1887,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
prepd_fault:
spin_unlock_bh(&session->frwd_lock);
- spin_lock_bh(&session->back_lock);
iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
- spin_unlock_bh(&session->back_lock);
return 0;
fault:
@@ -1978,39 +1975,43 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
static bool fail_scsi_task_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
{
- struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+ struct iscsi_task *task = scsi_cmd_priv(sc);
struct iscsi_sc_iter_data *iter_data = data;
struct iscsi_conn *conn = iter_data->conn;
struct iscsi_session *session = conn->session;
ISCSI_DBG_SESSION(session, "failing sc %p itt 0x%x state %d\n",
task->sc, task->itt, task->state);
- __iscsi_get_task(task);
- spin_unlock_bh(&session->back_lock);
fail_scsi_task(task, *(int *)iter_data->data);
-
- spin_unlock_bh(&session->frwd_lock);
- iscsi_put_task(task);
- spin_lock_bh(&session->frwd_lock);
-
- spin_lock_bh(&session->back_lock);
return true;
}
static bool iscsi_sc_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
{
- struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+ struct iscsi_task *task = scsi_cmd_priv(sc);
struct iscsi_sc_iter_data *iter_data = data;
+ bool rc;
- if (!task || !task->sc || task->state == ISCSI_TASK_FREE ||
- task->conn != iter_data->conn)
+ spin_lock_bh(&task->lock);
+ if (!task->sc || iscsi_task_is_completed(task) ||
+ task->conn != iter_data->conn) {
+ spin_unlock_bh(&task->lock);
return true;
+ }
+ __iscsi_get_task(task);
+ spin_unlock_bh(&task->lock);
- if (iter_data->lun != -1 && iter_data->lun != task->sc->device->lun)
- return true;
+ if (iter_data->lun != -1 && iter_data->lun != task->sc->device->lun) {
+ rc = true;
+ goto put_task;
+ }
- return iter_data->fn(sc, iter_data, rsvd);
+ rc = iter_data->fn(sc, iter_data, rsvd);
+
+put_task:
+ iscsi_put_task(task);
+ return rc;
}
void iscsi_conn_for_each_sc(struct iscsi_conn *conn,
@@ -2020,9 +2021,7 @@ void iscsi_conn_for_each_sc(struct iscsi_conn *conn,
struct Scsi_Host *shost = session->host;
iter_data->conn = conn;
- spin_lock_bh(&session->back_lock);
scsi_host_busy_iter(shost, iscsi_sc_iter, iter_data);
- spin_unlock_bh(&session->back_lock);
}
EXPORT_SYMBOL_GPL(iscsi_conn_for_each_sc);
@@ -2102,7 +2101,7 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
static bool check_scsi_task_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
{
- struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+ struct iscsi_task *task = scsi_cmd_priv(sc);
struct iscsi_sc_iter_data *iter_data = data;
struct iscsi_task *timed_out_task = iter_data->data;
@@ -2152,19 +2151,20 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
spin_lock_bh(&session->frwd_lock);
- spin_lock(&session->back_lock);
- task = (struct iscsi_task *)sc->SCp.ptr;
- if (!task) {
+
+ task = scsi_cmd_priv(sc);
+ spin_lock(&task->lock);
+ if (!task->sc || iscsi_task_is_completed(task)) {
/*
* Raced with completion. Blk layer has taken ownership
* so let timeout code complete it now.
*/
rc = BLK_EH_DONE;
- spin_unlock(&session->back_lock);
+ spin_unlock(&task->lock);
goto done;
}
__iscsi_get_task(task);
- spin_unlock(&session->back_lock);
+ spin_unlock(&task->lock);
if (READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN) {
/*
@@ -2336,20 +2336,37 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
+check_done:
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->frwd_lock);
/*
* if session was ISCSI_STATE_IN_RECOVERY then we may not have
* got the command.
*/
- if (!sc->SCp.ptr) {
+ task = scsi_cmd_priv(sc);
+ spin_lock_bh(&task->lock);
+ if (!task->sc) {
ISCSI_DBG_EH(session, "sc never reached iscsi layer or "
"it completed.\n");
+ spin_unlock_bh(&task->lock);
spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
return SUCCESS;
}
+ if (iscsi_task_is_completed(task)) {
+ spin_unlock_bh(&task->lock);
+ spin_unlock_bh(&session->frwd_lock);
+ mutex_unlock(&session->eh_mutex);
+
+ ISCSI_DBG_EH(session, "sc in process of completing. Waiting.\n");
+ msleep(100);
+ goto check_done;
+ }
+
+ __iscsi_get_task(task);
+ spin_unlock_bh(&task->lock);
+
/*
* If we are not logged in or we have started a new session
* then let the host reset code handle this
@@ -2357,6 +2374,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
if (!session->leadconn ||
READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN ||
sc->SCp.phase != session->age) {
+ iscsi_put_task(task);
spin_unlock_bh(&session->frwd_lock);
mutex_unlock(&session->eh_mutex);
ISCSI_DBG_EH(session, "failing abort due to dropped "
@@ -2368,25 +2386,16 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
conn->eh_abort_cnt++;
age = session->age;
- spin_lock(&session->back_lock);
- task = (struct iscsi_task *)sc->SCp.ptr;
- if (!task || !task->sc) {
- /* task completed before time out */
- ISCSI_DBG_EH(session, "sc completed while abort in progress\n");
-
- spin_unlock(&session->back_lock);
- spin_unlock_bh(&session->frwd_lock);
- mutex_unlock(&session->eh_mutex);
- return SUCCESS;
- }
ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", sc, task->itt);
- __iscsi_get_task(task);
- spin_unlock(&session->back_lock);
+ spin_lock_bh(&task->lock);
if (task->state == ISCSI_TASK_PENDING) {
+ spin_unlock_bh(&task->lock);
+
fail_scsi_task(task, DID_ABORT);
goto success;
}
+ spin_unlock_bh(&task->lock);
/* only have one tmf outstanding at a time */
if (conn->tmf_state != TMF_INITIAL)
@@ -2424,7 +2433,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
goto failed_unlocked;
case TMF_NOT_FOUND:
- if (!sc->SCp.ptr) {
+ if (!task->sc) {
conn->tmf_state = TMF_INITIAL;
memset(hdr, 0, sizeof(*hdr));
/* task completed before tmf abort response */
@@ -3334,27 +3343,28 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
for (i = 0; i < ISCSI_MGMT_CMDS_MAX; i++) {
task = conn->session->mgmt_cmds[i];
- if (task->sc)
- continue;
- if (task->state == ISCSI_TASK_FREE)
+ spin_lock_bh(&task->lock);
+ if (task->state == ISCSI_TASK_FREE) {
+ spin_unlock_bh(&task->lock);
continue;
+ }
ISCSI_DBG_SESSION(conn->session,
"failing mgmt itt 0x%x state %d\n",
task->itt, task->state);
- spin_lock_bh(&session->back_lock);
if (cleanup_queued_task(task)) {
- spin_unlock_bh(&session->back_lock);
+ spin_unlock_bh(&task->lock);
continue;
}
state = ISCSI_TASK_COMPLETED;
if (task->state == ISCSI_TASK_PENDING)
state = ISCSI_TASK_COMPLETED;
+ spin_unlock_bh(&task->lock);
+
iscsi_finish_task(task, state);
- spin_unlock_bh(&session->back_lock);
}
}
This replaces the back_lock with the per task lock for when we were checking the task->state/task->sc/SCp.ptr during error handling. Signed-off-by: Mike Christie <michael.christie@oracle.com> --- drivers/scsi/libiscsi.c | 132 +++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 61 deletions(-)