Skip to content

Commit

Permalink
scsi: qla2xxx: Fix premature command free
Browse files Browse the repository at this point in the history
When qla2xxx and Target Core gets out of sync during command cleanup, qla2xxx
will not free command until it is out of firmware's hand and Target Core has
called the release on the command.

This patch adds synchronization using cmd_lock and release flag.  If the
release flag is set, then qla2xxx will free up the command using
qlt_free_cmd() otherwise transport_generic_free_cmd() will be responsible for
relase of the command.

Signed-off-by: Quinn Tran <[email protected]>
Signed-off-by: Himanshu Madhani <[email protected]>
Signed-off-by: Martin K. Petersen <[email protected]>
  • Loading branch information
Quinn Tran authored and martinkpetersen committed Sep 12, 2018
1 parent 56d942d commit d594db0
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
4 changes: 4 additions & 0 deletions drivers/scsi/qla2xxx/qla_target.c
Original file line number Diff line number Diff line change
Expand Up @@ -3383,7 +3383,9 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,


cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */
spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
spin_unlock(&cmd->cmd_lock);
cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);

/* Memory Barrier */
Expand Down Expand Up @@ -3462,7 +3464,9 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
qlt_load_data_segments(&prm);

cmd->state = QLA_TGT_STATE_NEED_DATA;
spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
spin_unlock(&cmd->cmd_lock);
cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);

/* Memory Barrier */
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/qla2xxx/qla_target.h
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ struct qla_tgt_cmd {
unsigned int aborted:1;
unsigned int data_work:1;
unsigned int data_work_free:1;
unsigned int released:1;

struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
Expand Down
45 changes: 42 additions & 3 deletions drivers/scsi/qla2xxx/tcm_qla2xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,14 +277,25 @@ static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd)
static void tcm_qla2xxx_complete_free(struct work_struct *work)
{
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
bool released = false;
unsigned long flags;

cmd->cmd_in_wq = 0;

WARN_ON(cmd->trc_flags & TRC_CMD_FREE);

spin_lock_irqsave(&cmd->cmd_lock, flags);
cmd->qpair->tgt_counters.qla_core_ret_sta_ctio++;
cmd->trc_flags |= TRC_CMD_FREE;
transport_generic_free_cmd(&cmd->se_cmd, 0);
cmd->cmd_sent_to_fw = 0;
if (cmd->released)
released = true;
spin_unlock_irqrestore(&cmd->cmd_lock, flags);

if (released)
qlt_free_cmd(cmd);
else
transport_generic_free_cmd(&cmd->se_cmd, 0);
}

/*
Expand Down Expand Up @@ -325,16 +336,24 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd)
static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd)
{
struct qla_tgt_cmd *cmd;
unsigned long flags;

if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) {
struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd,
struct qla_tgt_mgmt_cmd, se_cmd);
qlt_free_mcmd(mcmd);
return;
}

cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd);
qlt_free_cmd(cmd);

spin_lock_irqsave(&cmd->cmd_lock, flags);
if (cmd->cmd_sent_to_fw) {
cmd->released = 1;
spin_unlock_irqrestore(&cmd->cmd_lock, flags);
} else {
spin_unlock_irqrestore(&cmd->cmd_lock, flags);
qlt_free_cmd(cmd);
}
}

static void tcm_qla2xxx_release_session(struct kref *kref)
Expand Down Expand Up @@ -499,13 +518,33 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
{
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
unsigned long flags;

/*
* Ensure that the complete FCP WRITE payload has been received.
* Otherwise return an exception via CHECK_CONDITION status.
*/
cmd->cmd_in_wq = 0;

spin_lock_irqsave(&cmd->cmd_lock, flags);
cmd->cmd_sent_to_fw = 0;

if (cmd->released) {
spin_unlock_irqrestore(&cmd->cmd_lock, flags);
qlt_free_cmd(cmd);
return;
}

cmd->data_work = 1;
if (cmd->aborted) {
cmd->data_work_free = 1;
spin_unlock_irqrestore(&cmd->cmd_lock, flags);

tcm_qla2xxx_free_cmd(cmd);
return;
}
spin_unlock_irqrestore(&cmd->cmd_lock, flags);

cmd->qpair->tgt_counters.qla_core_ret_ctio++;
if (!cmd->write_data_transferred) {
/*
Expand Down

0 comments on commit d594db0

Please sign in to comment.