Due to the previous patch if the session command list is empty that means that processing of all commands associated with a session has finished. Use this property to simplify the session shutdown code. Instead of using one completion object per command to wait for session shutdown, use one completion object per session. Signed-off-by: Bart Van Assche <bart.vanassche@xxxxxxxxxxx> --- drivers/target/target_core_transport.c | 66 +++++++++++++--------------------- include/target/target_core_base.h | 4 +-- 2 files changed, 25 insertions(+), 45 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 1daa9d3..0350380 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -251,7 +251,7 @@ struct se_session *transport_init_session(enum target_prot_op sup_prot_ops) 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); + init_completion(&se_sess->finished); spin_lock_init(&se_sess->sess_cmd_lock); kref_init(&se_sess->sess_kref); se_sess->sup_prot_ops = sup_prot_ops; @@ -1122,7 +1122,6 @@ void transport_init_se_cmd( INIT_LIST_HEAD(&cmd->se_qf_node); INIT_LIST_HEAD(&cmd->se_cmd_list); INIT_LIST_HEAD(&cmd->state_list_entry); - init_completion(&cmd->cmd_wait_comp); spin_lock_init(&cmd->t_state_lock); kref_init(&cmd->cmd_kref); cmd->transport_state = CMD_T_DEV_ACTIVE; @@ -2460,13 +2459,11 @@ static void target_release_cmd_kref(struct kref *kref) se_cmd->se_tfo->release_cmd(se_cmd); return; } - if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { - complete(&se_cmd->cmd_wait_comp); - return; - } spin_lock(&se_sess->sess_cmd_lock); list_del(&se_cmd->se_cmd_list); + if (list_empty(&se_sess->sess_cmd_list)) + complete(&se_sess->finished); spin_unlock(&se_sess->sess_cmd_lock); for (i = 0; i < se_cmd->cb_count; i++) { @@ -2497,59 +2494,44 @@ int target_put_sess_cmd(struct se_cmd *se_cmd) } EXPORT_SYMBOL(target_put_sess_cmd); -/* target_sess_cmd_list_set_waiting - Flag all commands in - * sess_cmd_list to complete cmd_wait_comp. Set - * sess_tearing_down so no more commands are queued. - * @se_sess: session to flag +/** + * target_sess_cmd_list_set_waiting - prepare session shutdown + * @se_sess: session to shut down */ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) { - struct se_cmd *se_cmd; unsigned long flags; + WARN_ON_ONCE(se_sess->sess_tearing_down); + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - 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_wait_list, se_cmd_list) - se_cmd->cmd_wait_set = 1; - spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); +static void target_show_sess_cmds(struct se_session *sess) +{ + struct se_cmd *cmd; + unsigned long flags; + + spin_lock_irqsave(&sess->sess_cmd_lock, flags); + list_for_each_entry(cmd, &sess->sess_cmd_list, se_cmd_list) + pr_info("Waiting for cmd %p; t_state %d; fabric state %d\n", + cmd, cmd->t_state, cmd->se_tfo->get_cmd_state(cmd)); + spin_unlock_irqrestore(&sess->sess_cmd_lock, flags); +} + /* target_wait_for_sess_cmds - Wait for outstanding descriptors * @se_sess: session to wait for active I/O */ void target_wait_for_sess_cmds(struct se_session *se_sess) { - struct se_cmd *se_cmd, *tmp_cmd; - unsigned long flags; - - list_for_each_entry_safe(se_cmd, tmp_cmd, - &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)); - - 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); + while (wait_for_completion_interruptible_timeout(&se_sess->finished, + 30 * HZ) <= 0) { + pr_info("Waiting for session shutdown\n"); + target_show_sess_cmds(se_sess); } - - 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); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index bf10b29..27f5db6 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -492,7 +492,6 @@ struct se_cmd { unsigned int map_tag; /* Transport protocol dependent state, see transport_state_table */ enum transport_state_table t_state; - unsigned cmd_wait_set:1; unsigned unknown_data_length:1; unsigned send_abort_response:1; /* See se_cmd_flags_table */ @@ -514,7 +513,6 @@ struct se_cmd { struct se_session *se_sess; struct se_tmr_req *se_tmr_req; struct list_head se_cmd_list; - struct completion cmd_wait_comp; struct kref cmd_kref; const struct target_core_fabric_ops *se_tfo; sense_reason_t (*execute_cmd)(struct se_cmd *); @@ -614,7 +612,7 @@ struct se_session { struct list_head sess_list; struct list_head sess_acl_list; struct list_head sess_cmd_list; - struct list_head sess_wait_list; + struct completion finished; spinlock_t sess_cmd_lock; struct kref sess_kref; void *sess_cmd_map; -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html