|
@@ -65,7 +65,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd);
|
|
|
static void transport_handle_queue_full(struct se_cmd *cmd,
|
|
|
struct se_device *dev);
|
|
|
static int transport_generic_get_mem(struct se_cmd *cmd);
|
|
|
-static void transport_put_cmd(struct se_cmd *cmd);
|
|
|
+static int transport_put_cmd(struct se_cmd *cmd);
|
|
|
static void target_complete_ok_work(struct work_struct *work);
|
|
|
|
|
|
int init_se_kmem_caches(void)
|
|
@@ -221,6 +221,7 @@ struct se_session *transport_init_session(void)
|
|
|
INIT_LIST_HEAD(&se_sess->sess_list);
|
|
|
INIT_LIST_HEAD(&se_sess->sess_acl_list);
|
|
|
INIT_LIST_HEAD(&se_sess->sess_cmd_list);
|
|
|
+ INIT_LIST_HEAD(&se_sess->sess_wait_list);
|
|
|
spin_lock_init(&se_sess->sess_cmd_lock);
|
|
|
kref_init(&se_sess->sess_kref);
|
|
|
|
|
@@ -1943,7 +1944,7 @@ static inline void transport_free_pages(struct se_cmd *cmd)
|
|
|
* This routine unconditionally frees a command, and reference counting
|
|
|
* or list removal must be done in the caller.
|
|
|
*/
|
|
|
-static void transport_release_cmd(struct se_cmd *cmd)
|
|
|
+static int transport_release_cmd(struct se_cmd *cmd)
|
|
|
{
|
|
|
BUG_ON(!cmd->se_tfo);
|
|
|
|
|
@@ -1955,11 +1956,11 @@ static void transport_release_cmd(struct se_cmd *cmd)
|
|
|
* If this cmd has been setup with target_get_sess_cmd(), drop
|
|
|
* the kref and call ->release_cmd() in kref callback.
|
|
|
*/
|
|
|
- if (cmd->check_release != 0) {
|
|
|
- target_put_sess_cmd(cmd->se_sess, cmd);
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (cmd->check_release != 0)
|
|
|
+ return target_put_sess_cmd(cmd->se_sess, cmd);
|
|
|
+
|
|
|
cmd->se_tfo->release_cmd(cmd);
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1968,7 +1969,7 @@ static void transport_release_cmd(struct se_cmd *cmd)
|
|
|
*
|
|
|
* This routine releases our reference to the command and frees it if possible.
|
|
|
*/
|
|
|
-static void transport_put_cmd(struct se_cmd *cmd)
|
|
|
+static int transport_put_cmd(struct se_cmd *cmd)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
|
|
@@ -1976,7 +1977,7 @@ static void transport_put_cmd(struct se_cmd *cmd)
|
|
|
if (atomic_read(&cmd->t_fe_count) &&
|
|
|
!atomic_dec_and_test(&cmd->t_fe_count)) {
|
|
|
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
|
|
@@ -1986,8 +1987,7 @@ static void transport_put_cmd(struct se_cmd *cmd)
|
|
|
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
|
|
|
|
|
transport_free_pages(cmd);
|
|
|
- transport_release_cmd(cmd);
|
|
|
- return;
|
|
|
+ return transport_release_cmd(cmd);
|
|
|
}
|
|
|
|
|
|
void *transport_kmap_data_sg(struct se_cmd *cmd)
|
|
@@ -2152,13 +2152,15 @@ static void transport_write_pending_qf(struct se_cmd *cmd)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
|
|
|
+int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
|
|
|
{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
|
|
|
if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
|
|
|
transport_wait_for_tasks(cmd);
|
|
|
|
|
|
- transport_release_cmd(cmd);
|
|
|
+ ret = transport_release_cmd(cmd);
|
|
|
} else {
|
|
|
if (wait_for_tasks)
|
|
|
transport_wait_for_tasks(cmd);
|
|
@@ -2166,8 +2168,9 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
|
|
|
if (cmd->se_lun)
|
|
|
transport_lun_remove_cmd(cmd);
|
|
|
|
|
|
- transport_put_cmd(cmd);
|
|
|
+ ret = transport_put_cmd(cmd);
|
|
|
}
|
|
|
+ return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(transport_generic_free_cmd);
|
|
|
|
|
@@ -2250,11 +2253,14 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
|
|
|
unsigned long flags;
|
|
|
|
|
|
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
|
|
|
-
|
|
|
- WARN_ON(se_sess->sess_tearing_down);
|
|
|
+ if (se_sess->sess_tearing_down) {
|
|
|
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
|
|
|
+ return;
|
|
|
+ }
|
|
|
se_sess->sess_tearing_down = 1;
|
|
|
+ list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
|
|
|
|
|
|
- list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list)
|
|
|
+ list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
|
|
|
se_cmd->cmd_wait_set = 1;
|
|
|
|
|
|
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
|
|
@@ -2263,44 +2269,32 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
|
|
|
|
|
|
/* target_wait_for_sess_cmds - Wait for outstanding descriptors
|
|
|
* @se_sess: session to wait for active I/O
|
|
|
- * @wait_for_tasks: Make extra transport_wait_for_tasks call
|
|
|
*/
|
|
|
-void target_wait_for_sess_cmds(
|
|
|
- struct se_session *se_sess,
|
|
|
- int wait_for_tasks)
|
|
|
+void target_wait_for_sess_cmds(struct se_session *se_sess)
|
|
|
{
|
|
|
struct se_cmd *se_cmd, *tmp_cmd;
|
|
|
- bool rc = false;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
list_for_each_entry_safe(se_cmd, tmp_cmd,
|
|
|
- &se_sess->sess_cmd_list, se_cmd_list) {
|
|
|
+ &se_sess->sess_wait_list, se_cmd_list) {
|
|
|
list_del(&se_cmd->se_cmd_list);
|
|
|
|
|
|
pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
|
|
|
" %d\n", se_cmd, se_cmd->t_state,
|
|
|
se_cmd->se_tfo->get_cmd_state(se_cmd));
|
|
|
|
|
|
- if (wait_for_tasks) {
|
|
|
- pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d,"
|
|
|
- " fabric state: %d\n", se_cmd, se_cmd->t_state,
|
|
|
- se_cmd->se_tfo->get_cmd_state(se_cmd));
|
|
|
-
|
|
|
- rc = transport_wait_for_tasks(se_cmd);
|
|
|
-
|
|
|
- pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d,"
|
|
|
- " fabric state: %d\n", se_cmd, se_cmd->t_state,
|
|
|
- se_cmd->se_tfo->get_cmd_state(se_cmd));
|
|
|
- }
|
|
|
-
|
|
|
- if (!rc) {
|
|
|
- wait_for_completion(&se_cmd->cmd_wait_comp);
|
|
|
- pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
|
|
|
- " fabric state: %d\n", se_cmd, se_cmd->t_state,
|
|
|
- se_cmd->se_tfo->get_cmd_state(se_cmd));
|
|
|
- }
|
|
|
+ wait_for_completion(&se_cmd->cmd_wait_comp);
|
|
|
+ pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
|
|
|
+ " fabric state: %d\n", se_cmd, se_cmd->t_state,
|
|
|
+ se_cmd->se_tfo->get_cmd_state(se_cmd));
|
|
|
|
|
|
se_cmd->se_tfo->release_cmd(se_cmd);
|
|
|
}
|
|
|
+
|
|
|
+ spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
|
|
|
+ WARN_ON(!list_empty(&se_sess->sess_cmd_list));
|
|
|
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
|
|
|
+
|
|
|
}
|
|
|
EXPORT_SYMBOL(target_wait_for_sess_cmds);
|
|
|
|