aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/target/target_core_transport.c132
-rw-r--r--include/target/target_core_base.h9
-rw-r--r--include/target/target_core_fabric_ops.h4
-rw-r--r--include/target/target_core_transport.h6
4 files changed, 145 insertions, 6 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 81bc355be317..e84b26ffb17b 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -268,6 +268,9 @@ struct se_session *transport_init_session(void)
268 } 268 }
269 INIT_LIST_HEAD(&se_sess->sess_list); 269 INIT_LIST_HEAD(&se_sess->sess_list);
270 INIT_LIST_HEAD(&se_sess->sess_acl_list); 270 INIT_LIST_HEAD(&se_sess->sess_acl_list);
271 INIT_LIST_HEAD(&se_sess->sess_cmd_list);
272 INIT_LIST_HEAD(&se_sess->sess_wait_list);
273 spin_lock_init(&se_sess->sess_cmd_lock);
271 274
272 return se_sess; 275 return se_sess;
273} 276}
@@ -1505,11 +1508,12 @@ void transport_init_se_cmd(
1505 INIT_LIST_HEAD(&cmd->se_ordered_node); 1508 INIT_LIST_HEAD(&cmd->se_ordered_node);
1506 INIT_LIST_HEAD(&cmd->se_qf_node); 1509 INIT_LIST_HEAD(&cmd->se_qf_node);
1507 INIT_LIST_HEAD(&cmd->se_queue_node); 1510 INIT_LIST_HEAD(&cmd->se_queue_node);
1508 1511 INIT_LIST_HEAD(&cmd->se_cmd_list);
1509 INIT_LIST_HEAD(&cmd->t_task_list); 1512 INIT_LIST_HEAD(&cmd->t_task_list);
1510 init_completion(&cmd->transport_lun_fe_stop_comp); 1513 init_completion(&cmd->transport_lun_fe_stop_comp);
1511 init_completion(&cmd->transport_lun_stop_comp); 1514 init_completion(&cmd->transport_lun_stop_comp);
1512 init_completion(&cmd->t_transport_stop_comp); 1515 init_completion(&cmd->t_transport_stop_comp);
1516 init_completion(&cmd->cmd_wait_comp);
1513 spin_lock_init(&cmd->t_state_lock); 1517 spin_lock_init(&cmd->t_state_lock);
1514 atomic_set(&cmd->transport_dev_active, 1); 1518 atomic_set(&cmd->transport_dev_active, 1);
1515 1519
@@ -3950,6 +3954,14 @@ void transport_release_cmd(struct se_cmd *cmd)
3950 core_tmr_release_req(cmd->se_tmr_req); 3954 core_tmr_release_req(cmd->se_tmr_req);
3951 if (cmd->t_task_cdb != cmd->__t_task_cdb) 3955 if (cmd->t_task_cdb != cmd->__t_task_cdb)
3952 kfree(cmd->t_task_cdb); 3956 kfree(cmd->t_task_cdb);
3957 /*
3958 * Check if target_wait_for_sess_cmds() is expecting to
3959 * release se_cmd directly here..
3960 */
3961 if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd)
3962 if (cmd->se_tfo->check_release_cmd(cmd) != 0)
3963 return;
3964
3953 cmd->se_tfo->release_cmd(cmd); 3965 cmd->se_tfo->release_cmd(cmd);
3954} 3966}
3955EXPORT_SYMBOL(transport_release_cmd); 3967EXPORT_SYMBOL(transport_release_cmd);
@@ -3977,6 +3989,114 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
3977} 3989}
3978EXPORT_SYMBOL(transport_generic_free_cmd); 3990EXPORT_SYMBOL(transport_generic_free_cmd);
3979 3991
3992/* target_get_sess_cmd - Add command to active ->sess_cmd_list
3993 * @se_sess: session to reference
3994 * @se_cmd: command descriptor to add
3995 */
3996void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
3997{
3998 unsigned long flags;
3999
4000 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
4001 list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
4002 se_cmd->check_release = 1;
4003 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
4004}
4005EXPORT_SYMBOL(target_get_sess_cmd);
4006
4007/* target_put_sess_cmd - Check for active I/O shutdown or list delete
4008 * @se_sess: session to reference
4009 * @se_cmd: command descriptor to drop
4010 */
4011int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
4012{
4013 unsigned long flags;
4014
4015 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
4016 if (list_empty(&se_cmd->se_cmd_list)) {
4017 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
4018 WARN_ON(1);
4019 return 0;
4020 }
4021
4022 if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
4023 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
4024 complete(&se_cmd->cmd_wait_comp);
4025 return 1;
4026 }
4027 list_del(&se_cmd->se_cmd_list);
4028 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
4029
4030 return 0;
4031}
4032EXPORT_SYMBOL(target_put_sess_cmd);
4033
4034/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list
4035 * @se_sess: session to split
4036 */
4037void target_splice_sess_cmd_list(struct se_session *se_sess)
4038{
4039 struct se_cmd *se_cmd;
4040 unsigned long flags;
4041
4042 WARN_ON(!list_empty(&se_sess->sess_wait_list));
4043 INIT_LIST_HEAD(&se_sess->sess_wait_list);
4044
4045 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
4046 se_sess->sess_tearing_down = 1;
4047
4048 list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
4049
4050 list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
4051 se_cmd->cmd_wait_set = 1;
4052
4053 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
4054}
4055EXPORT_SYMBOL(target_splice_sess_cmd_list);
4056
4057/* target_wait_for_sess_cmds - Wait for outstanding descriptors
4058 * @se_sess: session to wait for active I/O
4059 * @wait_for_tasks: Make extra transport_wait_for_tasks call
4060 */
4061void target_wait_for_sess_cmds(
4062 struct se_session *se_sess,
4063 int wait_for_tasks)
4064{
4065 struct se_cmd *se_cmd, *tmp_cmd;
4066 bool rc = false;
4067
4068 list_for_each_entry_safe(se_cmd, tmp_cmd,
4069 &se_sess->sess_wait_list, se_cmd_list) {
4070 list_del(&se_cmd->se_cmd_list);
4071
4072 pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
4073 " %d\n", se_cmd, se_cmd->t_state,
4074 se_cmd->se_tfo->get_cmd_state(se_cmd));
4075
4076 if (wait_for_tasks) {
4077 pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d,"
4078 " fabric state: %d\n", se_cmd, se_cmd->t_state,
4079 se_cmd->se_tfo->get_cmd_state(se_cmd));
4080
4081 rc = transport_wait_for_tasks(se_cmd);
4082
4083 pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d,"
4084 " fabric state: %d\n", se_cmd, se_cmd->t_state,
4085 se_cmd->se_tfo->get_cmd_state(se_cmd));
4086 }
4087
4088 if (!rc) {
4089 wait_for_completion(&se_cmd->cmd_wait_comp);
4090 pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
4091 " fabric state: %d\n", se_cmd, se_cmd->t_state,
4092 se_cmd->se_tfo->get_cmd_state(se_cmd));
4093 }
4094
4095 se_cmd->se_tfo->release_cmd(se_cmd);
4096 }
4097}
4098EXPORT_SYMBOL(target_wait_for_sess_cmds);
4099
3980/* transport_lun_wait_for_tasks(): 4100/* transport_lun_wait_for_tasks():
3981 * 4101 *
3982 * Called from ConfigFS context to stop the passed struct se_cmd to allow 4102 * Called from ConfigFS context to stop the passed struct se_cmd to allow
@@ -4153,14 +4273,14 @@ int transport_clear_lun_from_sessions(struct se_lun *lun)
4153 * Called from frontend fabric context to wait for storage engine 4273 * Called from frontend fabric context to wait for storage engine
4154 * to pause and/or release frontend generated struct se_cmd. 4274 * to pause and/or release frontend generated struct se_cmd.
4155 */ 4275 */
4156void transport_wait_for_tasks(struct se_cmd *cmd) 4276bool transport_wait_for_tasks(struct se_cmd *cmd)
4157{ 4277{
4158 unsigned long flags; 4278 unsigned long flags;
4159 4279
4160 spin_lock_irqsave(&cmd->t_state_lock, flags); 4280 spin_lock_irqsave(&cmd->t_state_lock, flags);
4161 if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) { 4281 if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) {
4162 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 4282 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
4163 return; 4283 return false;
4164 } 4284 }
4165 /* 4285 /*
4166 * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE 4286 * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE
@@ -4168,7 +4288,7 @@ void transport_wait_for_tasks(struct se_cmd *cmd)
4168 */ 4288 */
4169 if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) { 4289 if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) {
4170 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 4290 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
4171 return; 4291 return false;
4172 } 4292 }
4173 /* 4293 /*
4174 * If we are already stopped due to an external event (ie: LUN shutdown) 4294 * If we are already stopped due to an external event (ie: LUN shutdown)
@@ -4211,7 +4331,7 @@ void transport_wait_for_tasks(struct se_cmd *cmd)
4211 if (!atomic_read(&cmd->t_transport_active) || 4331 if (!atomic_read(&cmd->t_transport_active) ||
4212 atomic_read(&cmd->t_transport_aborted)) { 4332 atomic_read(&cmd->t_transport_aborted)) {
4213 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 4333 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
4214 return; 4334 return false;
4215 } 4335 }
4216 4336
4217 atomic_set(&cmd->t_transport_stop, 1); 4337 atomic_set(&cmd->t_transport_stop, 1);
@@ -4236,6 +4356,8 @@ void transport_wait_for_tasks(struct se_cmd *cmd)
4236 cmd->se_tfo->get_task_tag(cmd)); 4356 cmd->se_tfo->get_task_tag(cmd));
4237 4357
4238 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 4358 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
4359
4360 return true;
4239} 4361}
4240EXPORT_SYMBOL(transport_wait_for_tasks); 4362EXPORT_SYMBOL(transport_wait_for_tasks);
4241 4363
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index d571bcfd16ad..dd245b68be5a 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -425,6 +425,9 @@ struct se_cmd {
425 enum transport_state_table t_state; 425 enum transport_state_table t_state;
426 /* Transport specific error status */ 426 /* Transport specific error status */
427 int transport_error_status; 427 int transport_error_status;
428 /* Used to signal cmd->se_tfo->check_release_cmd() usage per cmd */
429 int check_release:1;
430 int cmd_wait_set:1;
428 /* See se_cmd_flags_table */ 431 /* See se_cmd_flags_table */
429 u32 se_cmd_flags; 432 u32 se_cmd_flags;
430 u32 se_ordered_id; 433 u32 se_ordered_id;
@@ -451,6 +454,8 @@ struct se_cmd {
451 struct se_session *se_sess; 454 struct se_session *se_sess;
452 struct se_tmr_req *se_tmr_req; 455 struct se_tmr_req *se_tmr_req;
453 struct list_head se_queue_node; 456 struct list_head se_queue_node;
457 struct list_head se_cmd_list;
458 struct completion cmd_wait_comp;
454 struct target_core_fabric_ops *se_tfo; 459 struct target_core_fabric_ops *se_tfo;
455 int (*transport_emulate_cdb)(struct se_cmd *); 460 int (*transport_emulate_cdb)(struct se_cmd *);
456 void (*transport_complete_callback)(struct se_cmd *); 461 void (*transport_complete_callback)(struct se_cmd *);
@@ -558,12 +563,16 @@ struct se_node_acl {
558} ____cacheline_aligned; 563} ____cacheline_aligned;
559 564
560struct se_session { 565struct se_session {
566 int sess_tearing_down:1;
561 u64 sess_bin_isid; 567 u64 sess_bin_isid;
562 struct se_node_acl *se_node_acl; 568 struct se_node_acl *se_node_acl;
563 struct se_portal_group *se_tpg; 569 struct se_portal_group *se_tpg;
564 void *fabric_sess_ptr; 570 void *fabric_sess_ptr;
565 struct list_head sess_list; 571 struct list_head sess_list;
566 struct list_head sess_acl_list; 572 struct list_head sess_acl_list;
573 struct list_head sess_cmd_list;
574 struct list_head sess_wait_list;
575 spinlock_t sess_cmd_lock;
567} ____cacheline_aligned; 576} ____cacheline_aligned;
568 577
569struct se_device; 578struct se_device;
diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h
index 04c591da0844..0256825f923d 100644
--- a/include/target/target_core_fabric_ops.h
+++ b/include/target/target_core_fabric_ops.h
@@ -52,6 +52,10 @@ struct target_core_fabric_ops {
52 * Returning 0 will signal a descriptor has not been released. 52 * Returning 0 will signal a descriptor has not been released.
53 */ 53 */
54 int (*check_stop_free)(struct se_cmd *); 54 int (*check_stop_free)(struct se_cmd *);
55 /*
56 * Optional check for active I/O shutdown
57 */
58 int (*check_release_cmd)(struct se_cmd *);
55 void (*release_cmd)(struct se_cmd *); 59 void (*release_cmd)(struct se_cmd *);
56 /* 60 /*
57 * Called with spin_lock_bh(struct se_portal_group->session_lock held. 61 * Called with spin_lock_bh(struct se_portal_group->session_lock held.
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h
index d1b68c9ccb75..c16e9431dd01 100644
--- a/include/target/target_core_transport.h
+++ b/include/target/target_core_transport.h
@@ -164,12 +164,16 @@ extern bool target_stop_task(struct se_task *task, unsigned long *flags);
164extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, 164extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
165 struct scatterlist *, u32); 165 struct scatterlist *, u32);
166extern int transport_clear_lun_from_sessions(struct se_lun *); 166extern int transport_clear_lun_from_sessions(struct se_lun *);
167extern void transport_wait_for_tasks(struct se_cmd *); 167extern bool transport_wait_for_tasks(struct se_cmd *);
168extern int transport_check_aborted_status(struct se_cmd *, int); 168extern int transport_check_aborted_status(struct se_cmd *, int);
169extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); 169extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
170extern void transport_send_task_abort(struct se_cmd *); 170extern void transport_send_task_abort(struct se_cmd *);
171extern void transport_release_cmd(struct se_cmd *); 171extern void transport_release_cmd(struct se_cmd *);
172extern void transport_generic_free_cmd(struct se_cmd *, int); 172extern void transport_generic_free_cmd(struct se_cmd *, int);
173extern void target_get_sess_cmd(struct se_session *, struct se_cmd *);
174extern int target_put_sess_cmd(struct se_session *, struct se_cmd *);
175extern void target_splice_sess_cmd_list(struct se_session *);
176extern void target_wait_for_sess_cmds(struct se_session *, int);
173extern void transport_generic_wait_for_cmds(struct se_cmd *, int); 177extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
174extern void transport_do_task_sg_chain(struct se_cmd *); 178extern void transport_do_task_sg_chain(struct se_cmd *);
175extern void transport_generic_process_write(struct se_cmd *); 179extern void transport_generic_process_write(struct se_cmd *);