@@ -267,9 +267,18 @@ int transport_alloc_session_tags(struct se_session *se_sess,
goto free_cmd_map;
}
+ se_sess->tmf_wq = alloc_workqueue("tmf-%p", WQ_UNBOUND, 1, se_sess);
+ if (!se_sess->tmf_wq) {
+ pr_err("%s: workqueue allocation failed\n", __func__);
+ goto free_tag_pool;
+ }
+
out:
return rc;
+free_tag_pool:
+ percpu_ida_destroy(&se_sess->sess_tag_pool);
+
free_cmd_map:
kvfree(se_sess->sess_cmd_map);
se_sess->sess_cmd_map = NULL;
@@ -511,6 +520,8 @@ void transport_free_session(struct se_session *se_sess)
se_sess->se_node_acl = NULL;
target_put_nacl(se_nacl);
}
+ if (se_sess->tmf_wq)
+ destroy_workqueue(se_sess->tmf_wq);
if (se_sess->sess_cmd_map) {
percpu_ida_destroy(&se_sess->sess_tag_pool);
kvfree(se_sess->sess_cmd_map);
@@ -3133,7 +3144,7 @@ int transport_generic_handle_tmr(
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
INIT_WORK(&cmd->work, target_tmr_work);
- queue_work(cmd->se_dev->tmr_wq, &cmd->work);
+ queue_work(cmd->se_sess->tmf_wq, &cmd->work);
return 0;
}
EXPORT_SYMBOL(transport_generic_handle_tmr);
@@ -606,6 +606,7 @@ struct se_session {
spinlock_t sess_cmd_lock;
void *sess_cmd_map;
struct percpu_ida sess_tag_pool;
+ struct workqueue_struct *tmf_wq;
};
struct se_device;
Several SCSI transport protocols require that SCSI task management functions are processed in the order in which these have been submitted by the initiator system. Hence introduce a workqueue per session for TMF processing. Do not specify WQ_MEM_RECLAIM since only the tcm_loop driver can queue TMF work from inside the memory allocation path and since the tcm_loop driver is only used to debug the SCSI target code. Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> --- Changes compared to v2 for this patch: test se_sess->tmf_wq before calling destroy_workqueue(). --- drivers/target/target_core_transport.c | 13 ++++++++++++- include/target/target_core_base.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-)