@@ -956,7 +956,7 @@ cxgbit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
return -1;
if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
- target_put_sess_cmd(&cmd->se_cmd);
+ iscsit_put_cmd(cmd);
return 0;
} else if (cmd->unsolicited_data) {
iscsit_set_unsoliticed_dataout(cmd);
@@ -872,8 +872,8 @@ static int iscsit_add_reject_from_cmd(
* scsit_setup_scsi_cmd()
*/
if (cmd->se_cmd.se_tfo != NULL) {
- pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
- target_put_sess_cmd(&cmd->se_cmd);
+ pr_debug("iscsi reject: calling iscsit_put_cmd() >>>>>>\n");
+ iscsit_put_cmd(cmd);
}
return -1;
}
@@ -1167,7 +1167,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length,
conn->cid);
- target_get_sess_cmd(&cmd->se_cmd, true);
+ iscsit_get_cmd(cmd);
cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd,
scsilun_to_int(&hdr->lun));
@@ -1235,7 +1235,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return -1;
else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
- target_put_sess_cmd(&cmd->se_cmd);
+ iscsit_put_cmd(cmd);
return 0;
}
}
@@ -1251,7 +1251,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (!cmd->sense_reason)
return 0;
- target_put_sess_cmd(&cmd->se_cmd);
+ iscsit_put_cmd(cmd);
return 0;
}
@@ -1308,7 +1308,7 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
rc = iscsit_dump_data_payload(cmd->conn,
cmd->first_burst_len, 1);
- target_put_sess_cmd(&cmd->se_cmd);
+ iscsit_put_cmd(cmd);
return rc;
} else if (cmd->unsolicited_data)
iscsit_set_unsoliticed_dataout(cmd);
@@ -2015,7 +2015,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
conn->sess->se_sess, 0, DMA_NONE,
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
- target_get_sess_cmd(&cmd->se_cmd, true);
+ iscsit_get_cmd(cmd);
sess_ref = true;
tcm_function = iscsit_convert_tmf(function);
if (tcm_function == TMR_UNKNOWN) {
@@ -2134,7 +2134,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
*/
if (sess_ref) {
pr_debug("Handle TMR, using sess_ref=true check\n");
- target_put_sess_cmd(&cmd->se_cmd);
+ iscsit_put_cmd(cmd);
}
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
@@ -1559,7 +1559,9 @@ static void lio_set_default_node_attributes(struct se_node_acl *se_acl)
static int lio_check_stop_free(struct se_cmd *se_cmd)
{
- return target_put_sess_cmd(se_cmd);
+ struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+ return iscsit_put_cmd(cmd);
}
static void lio_release_cmd(struct se_cmd *se_cmd)
@@ -688,6 +688,39 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
spin_unlock_bh(&conn->response_queue_lock);
}
+/**
+ * iscsit_get_cmd - add @cmd to the list of active commands
+ * @cmd: iSCSI command.
+ */
+int iscsit_get_cmd(struct iscsi_cmd *cmd)
+{
+ long refcnt = atomic_read(&cmd->refcnt);
+ int ret;
+
+ WARN_ONCE(refcnt != 0, "refcnt = %ld\n", refcnt);
+ ret = target_get_sess_cmd(&cmd->se_cmd, true);
+ if (ret)
+ return ret;
+ atomic_inc(&cmd->refcnt);
+ return ret;
+}
+
+/**
+ * iscsit_put_cmd() - decrease the reference count of @cmd
+ * @cmd: iSCSI command.
+ *
+ * Note: this function must be called only once per command.
+ */
+int iscsit_put_cmd(struct iscsi_cmd *cmd)
+{
+ long refcnt = atomic_read(&cmd->refcnt);
+
+ WARN_ONCE(refcnt <= 0, "refcnt = %ld\n", refcnt);
+ atomic_dec(&cmd->refcnt);
+ return target_put_sess_cmd(&cmd->se_cmd);
+}
+EXPORT_SYMBOL(iscsit_put_cmd);
+
void iscsit_release_cmd(struct iscsi_cmd *cmd)
{
struct iscsi_session *sess;
@@ -744,7 +777,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
__iscsit_free_cmd(cmd, shutdown);
- target_put_sess_cmd(se_cmd);
+ iscsit_put_cmd(cmd);
}
} else {
iscsit_release_cmd(cmd);
@@ -349,6 +349,7 @@ struct iscsi_r2t {
} ____cacheline_aligned;
struct iscsi_cmd {
+ atomic_t refcnt;
enum iscsi_timer_flags_table dataout_timer_flags;
/* DataOUT timeout retries */
u8 dataout_timeout_retries;
@@ -125,6 +125,8 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, int);
extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *,
unsigned char *, __be32);
+extern int iscsit_get_cmd(struct iscsi_cmd *cmd);
+extern int iscsit_put_cmd(struct iscsi_cmd *cmd);
extern void iscsit_release_cmd(struct iscsi_cmd *);
extern void iscsit_free_cmd(struct iscsi_cmd *, bool);
extern void iscsit_add_cmd_to_immediate_queue(struct iscsi_cmd *,
Keep track in .refcnt of whether or not target_put_sess_cmd() has already been called. Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> --- drivers/target/iscsi/cxgbit/cxgbit_target.c | 2 +- drivers/target/iscsi/iscsi_target.c | 16 ++++++------- drivers/target/iscsi/iscsi_target_configfs.c | 4 +++- drivers/target/iscsi/iscsi_target_util.c | 35 +++++++++++++++++++++++++++- include/target/iscsi/iscsi_target_core.h | 1 + include/target/iscsi/iscsi_transport.h | 2 ++ 6 files changed, 49 insertions(+), 11 deletions(-)