scsi: target: Drop sess_cmd_lock from I/O path
authorMike Christie <michael.christie@oracle.com>
Sun, 1 Nov 2020 18:59:32 +0000 (12:59 -0600)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 5 Nov 2020 03:39:37 +0000 (22:39 -0500)
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.com
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_sess.c
include/target/target_core_base.h
include/target/target_core_fabric.h

index a3ba0c4d0d3964ff7ce0039a30fd49864d1890ad..67f65dcb15a678bdd8570505f1082da71ec6bb6b 100644 (file)
@@ -2471,7 +2471,7 @@ isert_wait4cmds(struct iscsi_conn *conn)
        isert_info("iscsi_conn %p\n", conn);
 
        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);
        }
 }
index 0065eb17ae36b49ebb9097cee09ff7688f3fbf8c..8377113c85bafcd901f56a12bb0017e4539b561a 100644 (file)
@@ -2084,7 +2084,7 @@ static void srpt_release_channel_work(struct work_struct *w)
        se_sess = ch->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_remove_session(se_sess);
index e122da98eda71a6131caed77f00d300532eaccaf..784b43f18181896ca154d2af05cfeb28106c3566 100644 (file)
@@ -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)
 {
        struct fc_port *sess = se_sess->fabric_sess_ptr;
-       struct scsi_qla_host *vha;
-       unsigned long flags;
 
        BUG_ON(!sess);
-       vha = sess->vha;
 
-       spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
-       target_sess_cmd_list_set_waiting(se_sess);
-       spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+       target_stop_session(se_sess);
 
        sess->explicit_logout = 1;
        tcm_qla2xxx_put_sess(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)
 {
-       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,
index 62aa5fa63ac0978943b29411bf7fd1a579541cff..736847c933e5c1b4c3ede82866875e6c09419eec 100644 (file)
@@ -328,7 +328,7 @@ static void target_shutdown_sessions(struct se_node_acl *acl)
 restart:
        spin_lock_irqsave(&acl->nacl_sess_lock, flags);
        list_for_each_entry(sess, &acl->acl_sess_list, sess_acl_list) {
-               if (sess->sess_tearing_down)
+               if (atomic_read(&sess->stopped))
                        continue;
 
                list_del_init(&sess->sess_acl_list);
index faf1bab454d4fcf9e63a24d360d1b05ac7a30440..485317c020564ffc7b2c4206ce6d67ef34ca6f3d 100644 (file)
@@ -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);
 
-       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)
 {
        INIT_LIST_HEAD(&se_sess->sess_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);
-       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,
                               target_release_sess_cmd_refcnt, 0, GFP_KERNEL);
 }
@@ -239,11 +240,11 @@ EXPORT_SYMBOL(transport_init_session);
 void transport_uninit_session(struct se_session *se_sess)
 {
        /*
-        * Drivers like iscsi and loop do not call
-        * target_sess_cmd_list_set_waiting during session shutdown so we
-        * have to drop the ref taken at init time here.
+        * Drivers like iscsi and loop do not call target_stop_session
+        * during session shutdown so we have to drop the ref taken at init
+        * time here.
         */
-       if (!se_sess->sess_tearing_down)
+       if (!atomic_read(&se_sess->stopped))
                percpu_ref_put(&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
        if (flags & TARGET_SCF_UNKNOWN_SIZE)
                se_cmd->unknown_data_length = 1;
        /*
-        * Obtain struct se_cmd->cmd_kref reference and add new cmd to
-        * se_sess->sess_cmd_list.  A second kref_get here is necessary
-        * for fabrics using TARGET_SCF_ACK_KREF that expect a second
+        * Obtain struct se_cmd->cmd_kref reference. A second kref_get here is
+        * necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second
         * kref_put() to happen during fabric packet acknowledgement.
         */
        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)
 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
  * @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)
 {
        struct se_session *se_sess = se_cmd->se_sess;
-       unsigned long flags;
        int ret = 0;
 
        /*
@@ -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;
        }
 
-       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-       if (se_sess->sess_tearing_down) {
+       if (!percpu_ref_tryget_live(&se_sess->cmd_count))
                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)
                target_put_sess_cmd(se_cmd);
@@ -2818,13 +2810,6 @@ static void target_release_cmd_kref(struct kref *kref)
        struct se_session *se_sess = se_cmd->se_sess;
        struct completion *free_compl = se_cmd->free_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);
        se_cmd->se_tfo->release_cmd(se_cmd);
@@ -2952,21 +2937,25 @@ void target_show_cmd(const char *pfx, struct se_cmd *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.
- * @se_sess:   session to flag
+ * target_stop_session - Stop new IO from being queued on the session.
+ * @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;
-
-       spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-       se_sess->sess_tearing_down = 1;
-       spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-
-       percpu_ref_kill(&se_sess->cmd_count);
+       pr_debug("Stopping session queue.\n");
+       if (atomic_cmpxchg(&se_sess->stopped, 0, 1) == 0)
+               percpu_ref_kill_and_confirm(&se_sess->cmd_count,
+                                           target_stop_session_confirm);
 }
-EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
+EXPORT_SYMBOL(target_stop_session);
 
 /**
  * target_wait_for_sess_cmds - Wait for outstanding commands
@@ -2974,19 +2963,19 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
  */
 void target_wait_for_sess_cmds(struct se_session *se_sess)
 {
-       struct se_cmd *cmd;
        int ret;
 
-       WARN_ON_ONCE(!se_sess->sess_tearing_down);
+       WARN_ON_ONCE(!atomic_read(&se_sess->stopped));
 
        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),
                                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);
+
+       wait_for_completion(&se_sess->stop_done);
+       pr_debug("Waiting for cmds done.\n");
 }
 EXPORT_SYMBOL(target_wait_for_sess_cmds);
 
index 4fd6a1de947c2b4cf7b3ff3891cc1cddcbb8bff9..23ce506d5402bb1cb18aea56503f7b4523eff77f 100644 (file)
@@ -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)
 {
-       target_sess_cmd_list_set_waiting(sess->se_sess);
+       target_stop_session(sess->se_sess);
        target_wait_for_sess_cmds(sess->se_sess);
        ft_sess_put(sess);
 }
index 7d632593c398af84ee897294d0b39b05b9b157d3..c858dc060381563d596cafad4b27412e15c8bf08 100644 (file)
@@ -608,7 +608,7 @@ static inline struct se_node_acl *fabric_stat_to_nacl(struct config_item *item)
 }
 
 struct se_session {
-       unsigned                sess_tearing_down:1;
+       atomic_t                stopped;
        u64                     sess_bin_isid;
        enum target_prot_op     sup_prot_ops;
        enum target_prot_type   sess_prot_type;
@@ -618,9 +618,9 @@ struct se_session {
        struct percpu_ref       cmd_count;
        struct list_head        sess_list;
        struct list_head        sess_acl_list;
-       struct list_head        sess_cmd_list;
        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;
        struct sbitmap_queue    sess_tag_pool;
 };
index 6adf4d71acf6b7b7e3962627da46e2bcb1c7cb3c..d60a3eb7517abf6ba90838b274e47d8560dd5415 100644 (file)
@@ -178,7 +178,7 @@ int transport_send_check_condition_and_sense(struct se_cmd *,
 int    target_send_busy(struct se_cmd *cmd);
 int    target_get_sess_cmd(struct se_cmd *, bool);
 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_show_cmd(const char *pfx, struct se_cmd *cmd);