Commit 6f55b06f authored by Mike Christie's avatar Mike Christie Committed by Martin K. Petersen

scsi: target: Drop sess_cmd_lock from I/O path

Drop the sess_cmd_lock by:

 - Removing the sess_cmd_list use from LIO core, because it's been
   moved to qla2xxx.

 - Removing sess_tearing_down check in the I/O path. Instead of using that
   bit and the sess_cmd_lock, we rely on the cmd_count percpu ref. To do
   this we switch to percpu_ref_kill_and_confirm/percpu_ref_tryget_live.

Link: https://lore.kernel.org/r/1604257174-4524-7-git-send-email-michael.christie@oracle.comReviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: default avatarMike Christie <michael.christie@oracle.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 605e7402
...@@ -2471,7 +2471,7 @@ isert_wait4cmds(struct iscsi_conn *conn) ...@@ -2471,7 +2471,7 @@ isert_wait4cmds(struct iscsi_conn *conn)
isert_info("iscsi_conn %p\n", conn); isert_info("iscsi_conn %p\n", conn);
if (conn->sess) { if (conn->sess) {
target_sess_cmd_list_set_waiting(conn->sess->se_sess); target_stop_session(conn->sess->se_sess);
target_wait_for_sess_cmds(conn->sess->se_sess); target_wait_for_sess_cmds(conn->sess->se_sess);
} }
} }
......
...@@ -2084,7 +2084,7 @@ static void srpt_release_channel_work(struct work_struct *w) ...@@ -2084,7 +2084,7 @@ static void srpt_release_channel_work(struct work_struct *w)
se_sess = ch->sess; se_sess = ch->sess;
BUG_ON(!se_sess); BUG_ON(!se_sess);
target_sess_cmd_list_set_waiting(se_sess); target_stop_session(se_sess);
target_wait_for_sess_cmds(se_sess); target_wait_for_sess_cmds(se_sess);
target_remove_session(se_sess); target_remove_session(se_sess);
......
...@@ -368,15 +368,10 @@ static void tcm_qla2xxx_put_sess(struct fc_port *sess) ...@@ -368,15 +368,10 @@ static void tcm_qla2xxx_put_sess(struct fc_port *sess)
static void tcm_qla2xxx_close_session(struct se_session *se_sess) static void tcm_qla2xxx_close_session(struct se_session *se_sess)
{ {
struct fc_port *sess = se_sess->fabric_sess_ptr; struct fc_port *sess = se_sess->fabric_sess_ptr;
struct scsi_qla_host *vha;
unsigned long flags;
BUG_ON(!sess); BUG_ON(!sess);
vha = sess->vha;
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); target_stop_session(se_sess);
target_sess_cmd_list_set_waiting(se_sess);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
sess->explicit_logout = 1; sess->explicit_logout = 1;
tcm_qla2xxx_put_sess(sess); tcm_qla2xxx_put_sess(sess);
...@@ -831,7 +826,7 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct fc_port *sess) ...@@ -831,7 +826,7 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct fc_port *sess)
static void tcm_qla2xxx_shutdown_sess(struct fc_port *sess) static void tcm_qla2xxx_shutdown_sess(struct fc_port *sess)
{ {
target_sess_cmd_list_set_waiting(sess->se_sess); target_stop_session(sess->se_sess);
} }
static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl, static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl,
......
...@@ -328,7 +328,7 @@ static void target_shutdown_sessions(struct se_node_acl *acl) ...@@ -328,7 +328,7 @@ static void target_shutdown_sessions(struct se_node_acl *acl)
restart: restart:
spin_lock_irqsave(&acl->nacl_sess_lock, flags); spin_lock_irqsave(&acl->nacl_sess_lock, flags);
list_for_each_entry(sess, &acl->acl_sess_list, sess_acl_list) { list_for_each_entry(sess, &acl->acl_sess_list, sess_acl_list) {
if (sess->sess_tearing_down) if (atomic_read(&sess->stopped))
continue; continue;
list_del_init(&sess->sess_acl_list); list_del_init(&sess->sess_acl_list);
......
...@@ -215,7 +215,7 @@ static void target_release_sess_cmd_refcnt(struct percpu_ref *ref) ...@@ -215,7 +215,7 @@ static void target_release_sess_cmd_refcnt(struct percpu_ref *ref)
{ {
struct se_session *sess = container_of(ref, typeof(*sess), cmd_count); struct se_session *sess = container_of(ref, typeof(*sess), cmd_count);
wake_up(&sess->cmd_list_wq); wake_up(&sess->cmd_count_wq);
} }
/** /**
...@@ -228,9 +228,10 @@ int transport_init_session(struct se_session *se_sess) ...@@ -228,9 +228,10 @@ int transport_init_session(struct se_session *se_sess)
{ {
INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_list);
INIT_LIST_HEAD(&se_sess->sess_acl_list); INIT_LIST_HEAD(&se_sess->sess_acl_list);
INIT_LIST_HEAD(&se_sess->sess_cmd_list);
spin_lock_init(&se_sess->sess_cmd_lock); spin_lock_init(&se_sess->sess_cmd_lock);
init_waitqueue_head(&se_sess->cmd_list_wq); init_waitqueue_head(&se_sess->cmd_count_wq);
init_completion(&se_sess->stop_done);
atomic_set(&se_sess->stopped, 0);
return percpu_ref_init(&se_sess->cmd_count, return percpu_ref_init(&se_sess->cmd_count,
target_release_sess_cmd_refcnt, 0, GFP_KERNEL); target_release_sess_cmd_refcnt, 0, GFP_KERNEL);
} }
...@@ -239,11 +240,11 @@ EXPORT_SYMBOL(transport_init_session); ...@@ -239,11 +240,11 @@ EXPORT_SYMBOL(transport_init_session);
void transport_uninit_session(struct se_session *se_sess) void transport_uninit_session(struct se_session *se_sess)
{ {
/* /*
* Drivers like iscsi and loop do not call * Drivers like iscsi and loop do not call target_stop_session
* target_sess_cmd_list_set_waiting during session shutdown so we * during session shutdown so we have to drop the ref taken at init
* have to drop the ref taken at init time here. * time here.
*/ */
if (!se_sess->sess_tearing_down) if (!atomic_read(&se_sess->stopped))
percpu_ref_put(&se_sess->cmd_count); percpu_ref_put(&se_sess->cmd_count);
percpu_ref_exit(&se_sess->cmd_count); percpu_ref_exit(&se_sess->cmd_count);
...@@ -1632,9 +1633,8 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess ...@@ -1632,9 +1633,8 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
if (flags & TARGET_SCF_UNKNOWN_SIZE) if (flags & TARGET_SCF_UNKNOWN_SIZE)
se_cmd->unknown_data_length = 1; se_cmd->unknown_data_length = 1;
/* /*
* Obtain struct se_cmd->cmd_kref reference and add new cmd to * Obtain struct se_cmd->cmd_kref reference. A second kref_get here is
* se_sess->sess_cmd_list. A second kref_get here is necessary * necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second
* for fabrics using TARGET_SCF_ACK_KREF that expect a second
* kref_put() to happen during fabric packet acknowledgement. * kref_put() to happen during fabric packet acknowledgement.
*/ */
ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF); ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
...@@ -2763,14 +2763,13 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) ...@@ -2763,14 +2763,13 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
EXPORT_SYMBOL(transport_generic_free_cmd); EXPORT_SYMBOL(transport_generic_free_cmd);
/** /**
* target_get_sess_cmd - Add command to active ->sess_cmd_list * target_get_sess_cmd - Verify the session is accepting cmds and take ref
* @se_cmd: command descriptor to add * @se_cmd: command descriptor to add
* @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd()
*/ */
int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
{ {
struct se_session *se_sess = se_cmd->se_sess; struct se_session *se_sess = se_cmd->se_sess;
unsigned long flags;
int ret = 0; int ret = 0;
/* /*
...@@ -2785,15 +2784,8 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) ...@@ -2785,15 +2784,8 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
se_cmd->se_cmd_flags |= SCF_ACK_KREF; se_cmd->se_cmd_flags |= SCF_ACK_KREF;
} }
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (!percpu_ref_tryget_live(&se_sess->cmd_count))
if (se_sess->sess_tearing_down) {
ret = -ESHUTDOWN; ret = -ESHUTDOWN;
goto out;
}
list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
percpu_ref_get(&se_sess->cmd_count);
out:
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
if (ret && ack_kref) if (ret && ack_kref)
target_put_sess_cmd(se_cmd); target_put_sess_cmd(se_cmd);
...@@ -2818,13 +2810,6 @@ static void target_release_cmd_kref(struct kref *kref) ...@@ -2818,13 +2810,6 @@ static void target_release_cmd_kref(struct kref *kref)
struct se_session *se_sess = se_cmd->se_sess; struct se_session *se_sess = se_cmd->se_sess;
struct completion *free_compl = se_cmd->free_compl; struct completion *free_compl = se_cmd->free_compl;
struct completion *abrt_compl = se_cmd->abrt_compl; struct completion *abrt_compl = se_cmd->abrt_compl;
unsigned long flags;
if (se_sess) {
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
list_del_init(&se_cmd->se_cmd_list);
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
}
target_free_cmd_mem(se_cmd); target_free_cmd_mem(se_cmd);
se_cmd->se_tfo->release_cmd(se_cmd); se_cmd->se_tfo->release_cmd(se_cmd);
...@@ -2952,21 +2937,25 @@ void target_show_cmd(const char *pfx, struct se_cmd *cmd) ...@@ -2952,21 +2937,25 @@ void target_show_cmd(const char *pfx, struct se_cmd *cmd)
} }
EXPORT_SYMBOL(target_show_cmd); EXPORT_SYMBOL(target_show_cmd);
static void target_stop_session_confirm(struct percpu_ref *ref)
{
struct se_session *se_sess = container_of(ref, struct se_session,
cmd_count);
complete_all(&se_sess->stop_done);
}
/** /**
* target_sess_cmd_list_set_waiting - Set sess_tearing_down so no new commands are queued. * target_stop_session - Stop new IO from being queued on the session.
* @se_sess: session to flag * @se_sess: session to stop
*/ */
void target_sess_cmd_list_set_waiting(struct se_session *se_sess) void target_stop_session(struct se_session *se_sess)
{ {
unsigned long flags; pr_debug("Stopping session queue.\n");
if (atomic_cmpxchg(&se_sess->stopped, 0, 1) == 0)
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); percpu_ref_kill_and_confirm(&se_sess->cmd_count,
se_sess->sess_tearing_down = 1; target_stop_session_confirm);
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
percpu_ref_kill(&se_sess->cmd_count);
} }
EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); EXPORT_SYMBOL(target_stop_session);
/** /**
* target_wait_for_sess_cmds - Wait for outstanding commands * target_wait_for_sess_cmds - Wait for outstanding commands
...@@ -2974,19 +2963,19 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); ...@@ -2974,19 +2963,19 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
*/ */
void target_wait_for_sess_cmds(struct se_session *se_sess) void target_wait_for_sess_cmds(struct se_session *se_sess)
{ {
struct se_cmd *cmd;
int ret; int ret;
WARN_ON_ONCE(!se_sess->sess_tearing_down); WARN_ON_ONCE(!atomic_read(&se_sess->stopped));
do { do {
ret = wait_event_timeout(se_sess->cmd_list_wq, pr_debug("Waiting for running cmds to complete.\n");
ret = wait_event_timeout(se_sess->cmd_count_wq,
percpu_ref_is_zero(&se_sess->cmd_count), percpu_ref_is_zero(&se_sess->cmd_count),
180 * HZ); 180 * HZ);
list_for_each_entry(cmd, &se_sess->sess_cmd_list, se_cmd_list)
target_show_cmd("session shutdown: still waiting for ",
cmd);
} while (ret <= 0); } while (ret <= 0);
wait_for_completion(&se_sess->stop_done);
pr_debug("Waiting for cmds done.\n");
} }
EXPORT_SYMBOL(target_wait_for_sess_cmds); EXPORT_SYMBOL(target_wait_for_sess_cmds);
......
...@@ -275,7 +275,7 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) ...@@ -275,7 +275,7 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id)
static void ft_close_sess(struct ft_sess *sess) static void ft_close_sess(struct ft_sess *sess)
{ {
target_sess_cmd_list_set_waiting(sess->se_sess); target_stop_session(sess->se_sess);
target_wait_for_sess_cmds(sess->se_sess); target_wait_for_sess_cmds(sess->se_sess);
ft_sess_put(sess); ft_sess_put(sess);
} }
......
...@@ -608,7 +608,7 @@ static inline struct se_node_acl *fabric_stat_to_nacl(struct config_item *item) ...@@ -608,7 +608,7 @@ static inline struct se_node_acl *fabric_stat_to_nacl(struct config_item *item)
} }
struct se_session { struct se_session {
unsigned sess_tearing_down:1; atomic_t stopped;
u64 sess_bin_isid; u64 sess_bin_isid;
enum target_prot_op sup_prot_ops; enum target_prot_op sup_prot_ops;
enum target_prot_type sess_prot_type; enum target_prot_type sess_prot_type;
...@@ -618,9 +618,9 @@ struct se_session { ...@@ -618,9 +618,9 @@ struct se_session {
struct percpu_ref cmd_count; struct percpu_ref cmd_count;
struct list_head sess_list; struct list_head sess_list;
struct list_head sess_acl_list; struct list_head sess_acl_list;
struct list_head sess_cmd_list;
spinlock_t sess_cmd_lock; spinlock_t sess_cmd_lock;
wait_queue_head_t cmd_list_wq; wait_queue_head_t cmd_count_wq;
struct completion stop_done;
void *sess_cmd_map; void *sess_cmd_map;
struct sbitmap_queue sess_tag_pool; struct sbitmap_queue sess_tag_pool;
}; };
......
...@@ -178,7 +178,7 @@ int transport_send_check_condition_and_sense(struct se_cmd *, ...@@ -178,7 +178,7 @@ int transport_send_check_condition_and_sense(struct se_cmd *,
int target_send_busy(struct se_cmd *cmd); int target_send_busy(struct se_cmd *cmd);
int target_get_sess_cmd(struct se_cmd *, bool); int target_get_sess_cmd(struct se_cmd *, bool);
int target_put_sess_cmd(struct se_cmd *); int target_put_sess_cmd(struct se_cmd *);
void target_sess_cmd_list_set_waiting(struct se_session *); void target_stop_session(struct se_session *se_sess);
void target_wait_for_sess_cmds(struct se_session *); void target_wait_for_sess_cmds(struct se_session *);
void target_show_cmd(const char *pfx, struct se_cmd *cmd); void target_show_cmd(const char *pfx, struct se_cmd *cmd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment