Make transport_wait_for_tasks() use a completion that has been allocated on the stack instead of the t_transport_stop_comp member of struct se_cmd. Introduce a callback mechanism in struct se_cmd. This is a first step towards removing the t_transport_stop_comp member. That member variable cannot yet be removed via this patch because the tcm_qla2xxx driver uses it directly. Signed-off-by: Bart Van Assche <bart.vanassche@xxxxxxxxxxx> --- drivers/target/target_core_transport.c | 34 ++++++++++++++++++++++++++++++---- include/target/target_core_base.h | 12 ++++++++++++ include/target/target_core_fabric.h | 3 +++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 19c9241..3538a36 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -598,7 +598,6 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, spin_unlock_irqrestore(&cmd->t_state_lock, flags); - complete_all(&cmd->t_transport_stop_comp); return 1; } @@ -723,7 +722,6 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) if (cmd->transport_state & CMD_T_ABORTED && cmd->transport_state & CMD_T_STOP) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - complete_all(&cmd->t_transport_stop_comp); return; } else if (!success) { INIT_WORK(&cmd->work, target_complete_failure_work); @@ -1177,10 +1175,25 @@ void transport_init_se_cmd( cmd->sam_task_attr = task_attr; cmd->sense_buffer = sense_buffer; + cmd->cb_count = 0; cmd->state_active = false; } EXPORT_SYMBOL(transport_init_se_cmd); +void __target_add_cmd_cb(struct se_cmd *cmd, void (*done)(void *), + void *done_arg) +{ + int i; + + lockdep_assert_held(&cmd->t_state_lock); + + i = cmd->cb_count++; + BUG_ON(i >= ARRAY_SIZE(cmd->done_cb)); + cmd->done_cb[i].cb = done; + cmd->done_cb[i].arg = done_arg; +} +EXPORT_SYMBOL(__target_add_cmd_cb); + static sense_reason_t transport_check_alloc_task_attr(struct se_cmd *cmd) { @@ -1853,7 +1866,6 @@ void target_execute_cmd(struct se_cmd *cmd) __func__, __LINE__, cmd->tag); spin_unlock_irq(&cmd->t_state_lock); - complete_all(&cmd->t_transport_stop_comp); return; } @@ -2510,6 +2522,8 @@ static void target_release_cmd_kref(struct kref *kref) { struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); struct se_session *se_sess = se_cmd->se_sess; + struct se_cmd_done_cb *cbe; + int i; if (list_empty(&se_cmd->se_cmd_list)) { se_cmd->se_tfo->release_cmd(se_cmd); @@ -2524,6 +2538,11 @@ static void target_release_cmd_kref(struct kref *kref) list_del(&se_cmd->se_cmd_list); spin_unlock(&se_sess->sess_cmd_lock); + for (i = 0; i < se_cmd->cb_count; i++) { + cbe = &se_cmd->done_cb[i]; + cbe->cb(cbe->arg); + } + se_cmd->se_tfo->release_cmd(se_cmd); } @@ -2609,6 +2628,11 @@ void transport_clear_lun_ref(struct se_lun *lun) wait_for_completion(&lun->lun_ref_comp); } +static void target_cmd_done(void *arg) +{ + complete(arg); +} + /** * transport_wait_for_tasks - wait for completion to occur * @cmd: command to wait @@ -2618,6 +2642,7 @@ void transport_clear_lun_ref(struct se_lun *lun) */ bool transport_wait_for_tasks(struct se_cmd *cmd) { + DECLARE_COMPLETION_ONSTACK(cmd_done); unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); @@ -2643,9 +2668,10 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n", cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); + __target_add_cmd_cb(cmd, target_cmd_done, &cmd_done); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - wait_for_completion(&cmd->t_transport_stop_comp); + wait_for_completion(&cmd_done); spin_lock_irqsave(&cmd->t_state_lock, flags); cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 2b57314..65f7258 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -466,6 +466,16 @@ struct se_dif_v1_tuple { #define TCM_ORDERED_TAG 0x22 #define TCM_ACA_TAG 0x24 +/** + * struct se_cmd_done_cb - callback function invoked after a se_cmd finished + * @cb: Callback function. + * @cb_arg: Argument that will be passed to the callback function. + */ +struct se_cmd_done_cb { + void (*cb)(void *); + void *arg; +}; + struct se_cmd { /* SAM response code being sent to initiator */ u8 scsi_status; @@ -527,6 +537,8 @@ struct se_cmd { #define CMD_T_BUSY (1 << 9) spinlock_t t_state_lock; struct completion t_transport_stop_comp; + unsigned int cb_count; /* protected by t_state_lock */ + struct se_cmd_done_cb done_cb[1]; /* protected by t_state_lock */ struct work_struct work; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index ecaa792..33e98b9 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -131,6 +131,9 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, int transport_handle_cdb_direct(struct se_cmd *); sense_reason_t transport_generic_new_cmd(struct se_cmd *); +void __target_add_cmd_cb(struct se_cmd *cmd, void (*done)(void *), + void *done_arg); + void target_execute_cmd(struct se_cmd *cmd); int transport_generic_free_cmd(struct se_cmd *, int); -- 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