diff options
-rw-r--r-- | drivers/target/target_core_transport.c | 132 | ||||
-rw-r--r-- | include/target/target_core_base.h | 9 | ||||
-rw-r--r-- | include/target/target_core_fabric_ops.h | 4 | ||||
-rw-r--r-- | include/target/target_core_transport.h | 6 |
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 | } |
3955 | EXPORT_SYMBOL(transport_release_cmd); | 3967 | EXPORT_SYMBOL(transport_release_cmd); |
@@ -3977,6 +3989,114 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) | |||
3977 | } | 3989 | } |
3978 | EXPORT_SYMBOL(transport_generic_free_cmd); | 3990 | EXPORT_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 | */ | ||
3996 | void 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 | } | ||
4005 | EXPORT_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 | */ | ||
4011 | int 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 | } | ||
4032 | EXPORT_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 | */ | ||
4037 | void 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 | } | ||
4055 | EXPORT_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 | */ | ||
4061 | void 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 | } | ||
4098 | EXPORT_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 | */ |
4156 | void transport_wait_for_tasks(struct se_cmd *cmd) | 4276 | bool 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 | } |
4240 | EXPORT_SYMBOL(transport_wait_for_tasks); | 4362 | EXPORT_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 | ||
560 | struct se_session { | 565 | struct 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 | ||
569 | struct se_device; | 578 | struct 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); | |||
164 | extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, | 164 | extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, |
165 | struct scatterlist *, u32); | 165 | struct scatterlist *, u32); |
166 | extern int transport_clear_lun_from_sessions(struct se_lun *); | 166 | extern int transport_clear_lun_from_sessions(struct se_lun *); |
167 | extern void transport_wait_for_tasks(struct se_cmd *); | 167 | extern bool transport_wait_for_tasks(struct se_cmd *); |
168 | extern int transport_check_aborted_status(struct se_cmd *, int); | 168 | extern int transport_check_aborted_status(struct se_cmd *, int); |
169 | extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); | 169 | extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); |
170 | extern void transport_send_task_abort(struct se_cmd *); | 170 | extern void transport_send_task_abort(struct se_cmd *); |
171 | extern void transport_release_cmd(struct se_cmd *); | 171 | extern void transport_release_cmd(struct se_cmd *); |
172 | extern void transport_generic_free_cmd(struct se_cmd *, int); | 172 | extern void transport_generic_free_cmd(struct se_cmd *, int); |
173 | extern void target_get_sess_cmd(struct se_session *, struct se_cmd *); | ||
174 | extern int target_put_sess_cmd(struct se_session *, struct se_cmd *); | ||
175 | extern void target_splice_sess_cmd_list(struct se_session *); | ||
176 | extern void target_wait_for_sess_cmds(struct se_session *, int); | ||
173 | extern void transport_generic_wait_for_cmds(struct se_cmd *, int); | 177 | extern void transport_generic_wait_for_cmds(struct se_cmd *, int); |
174 | extern void transport_do_task_sg_chain(struct se_cmd *); | 178 | extern void transport_do_task_sg_chain(struct se_cmd *); |
175 | extern void transport_generic_process_write(struct se_cmd *); | 179 | extern void transport_generic_process_write(struct se_cmd *); |