diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-11-03 00:52:08 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-11-04 03:50:26 -0400 |
commit | a17f091d1a7c570804cfc2c77701634da88f8ecf (patch) | |
tree | 50884063148c31cb5ee7b9a3f13bcc41f585cb92 /include/target | |
parent | 2235007c4d3245c0eca5e49497aafe5a111c00fb (diff) |
target: Add generic active I/O shutdown logic
This patch adds the initial pieces of generic active I/O shutdown logic.
This is intended to be a 'opt-in' feature for fabric modules that
includes the following functions to provide a mechinism for fabric
modules to track se_cmd via se_session->sess_cmd_list:
*) target_get_sess_cmd() - Add se_cmd to sess->sess_cmd_list, called
from fabric module incoming I/O path.
*) target_put_sess_cmd() - Check for completion or drop se_cmd from
->sess_cmd_list
*) target_splice_sess_cmd_list() - Splice active I/O list from
->sess_cmd_list to ->sess_wait_list, can called with HW fabric
lock held.
*) target_wait_for_sess_cmds() - Walk ->sess_wait_list waiting on
individual ->cmd_wait_comp. Optional transport_wait_for_tasks()
call.
target_splice_sess_cmd_list() is allowed to be called under HW fabric
lock, and performs the splice into se_sess->sess_wait_list and set
se_cmd->cmd_wait_set. Then target_wait_for_sess_cmds() walks the list
waiting for individual target_put_sess_cmd() fabric callbacks to
complete.
It also adds TFO->check_release_cmd() to split the completion and memory
release calls, where a fabric module uses target_put_sess_cmd() to check
for I/O completion during session shutdown. This is currently pushed out
into fabric modules as current fabric code may sleep here waiting for
TFO->check_stop_free() to complete in main response path, and because
target_wait_for_sess_cmds() calling TFO->release_cmd() to free fabric
descriptor memory directly.
Cc: Christoph Hellwig <hch@lst.de>
Cc: Roland Dreier <roland@purestorage.com>
Signed-off-by: Nicholas A. Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'include/target')
-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 |
3 files changed, 18 insertions, 1 deletions
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 *); |