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>
This commit is contained in:
Nicholas Bellinger
2011-11-02 21:52:08 -07:00
parent 2235007c4d
commit a17f091d1a
4 changed files with 145 additions and 6 deletions
+9
View File
@@ -425,6 +425,9 @@ struct se_cmd {
enum transport_state_table t_state;
/* Transport specific error status */
int transport_error_status;
/* Used to signal cmd->se_tfo->check_release_cmd() usage per cmd */
int check_release:1;
int cmd_wait_set:1;
/* See se_cmd_flags_table */
u32 se_cmd_flags;
u32 se_ordered_id;
@@ -451,6 +454,8 @@ struct se_cmd {
struct se_session *se_sess;
struct se_tmr_req *se_tmr_req;
struct list_head se_queue_node;
struct list_head se_cmd_list;
struct completion cmd_wait_comp;
struct target_core_fabric_ops *se_tfo;
int (*transport_emulate_cdb)(struct se_cmd *);
void (*transport_complete_callback)(struct se_cmd *);
@@ -558,12 +563,16 @@ struct se_node_acl {
} ____cacheline_aligned;
struct se_session {
int sess_tearing_down:1;
u64 sess_bin_isid;
struct se_node_acl *se_node_acl;
struct se_portal_group *se_tpg;
void *fabric_sess_ptr;
struct list_head sess_list;
struct list_head sess_acl_list;
struct list_head sess_cmd_list;
struct list_head sess_wait_list;
spinlock_t sess_cmd_lock;
} ____cacheline_aligned;
struct se_device;
+4
View File
@@ -52,6 +52,10 @@ struct target_core_fabric_ops {
* Returning 0 will signal a descriptor has not been released.
*/
int (*check_stop_free)(struct se_cmd *);
/*
* Optional check for active I/O shutdown
*/
int (*check_release_cmd)(struct se_cmd *);
void (*release_cmd)(struct se_cmd *);
/*
* Called with spin_lock_bh(struct se_portal_group->session_lock held.
+5 -1
View File
@@ -164,12 +164,16 @@ extern bool target_stop_task(struct se_task *task, unsigned long *flags);
extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
struct scatterlist *, u32);
extern int transport_clear_lun_from_sessions(struct se_lun *);
extern void transport_wait_for_tasks(struct se_cmd *);
extern bool transport_wait_for_tasks(struct se_cmd *);
extern int transport_check_aborted_status(struct se_cmd *, int);
extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
extern void transport_send_task_abort(struct se_cmd *);
extern void transport_release_cmd(struct se_cmd *);
extern void transport_generic_free_cmd(struct se_cmd *, int);
extern void target_get_sess_cmd(struct se_session *, struct se_cmd *);
extern int target_put_sess_cmd(struct se_session *, struct se_cmd *);
extern void target_splice_sess_cmd_list(struct se_session *);
extern void target_wait_for_sess_cmds(struct se_session *, int);
extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
extern void transport_do_task_sg_chain(struct se_cmd *);
extern void transport_generic_process_write(struct se_cmd *);