target: Make target_put_sess_cmd use target_release_cmd_kref
authorNicholas Bellinger <nab@linux-iscsi.org>
Sat, 12 Nov 2011 08:32:17 +0000 (00:32 -0800)
committerNicholas Bellinger <nab@linux-iscsi.org>
Wed, 14 Dec 2011 11:38:29 +0000 (11:38 +0000)
This patch moves target_put_sess_cmd() to use a se_cmd->cmd_kref
callback target_release_cmd_kref when performing driver release of
fabric->se_cmd descriptor memory.  It sets the default cmd_kref
count value to '2' within target_get_sess_cmd() setup, and
currently assumes TFO->check_stop_free() usage.

It drops se_tfo->check_release_cmd() usage in the main
transport_release_cmd codepath.

Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/target_core_transport.c
include/target/target_core_base.h

index 122925686de256f153ddf45b8afd6f3f1185592f..176f956665e88889f952a1efd958d16da1815423 100644 (file)
@@ -3349,13 +3349,13 @@ static void transport_release_cmd(struct se_cmd *cmd)
        if (cmd->t_task_cdb != cmd->__t_task_cdb)
                kfree(cmd->t_task_cdb);
        /*
-        * Check if target_wait_for_sess_cmds() is expecting to
-        * release se_cmd directly here..
+        * If this cmd has been setup with target_get_sess_cmd(), drop
+        * the kref and call ->release_cmd() in kref callback.
         */
-       if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd)
-               if (cmd->se_tfo->check_release_cmd(cmd) != 0)
-                       return;
-
+        if (cmd->check_release != 0) {
+               target_put_sess_cmd(cmd->se_sess, cmd);
+               return;
+       }
        cmd->se_tfo->release_cmd(cmd);
 }
 
@@ -3915,6 +3915,9 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
 {
        unsigned long flags;
 
+       kref_init(&se_cmd->cmd_kref);
+       kref_get(&se_cmd->cmd_kref);
+
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
        se_cmd->check_release = 1;
@@ -3922,30 +3925,36 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
 
-/* target_put_sess_cmd - Check for active I/O shutdown or list delete
- * @se_sess:   session to reference
- * @se_cmd:    command descriptor to drop
- */
-int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
+static void target_release_cmd_kref(struct kref *kref)
 {
+       struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
+       struct se_session *se_sess = se_cmd->se_sess;
        unsigned long flags;
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (list_empty(&se_cmd->se_cmd_list)) {
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
                WARN_ON(1);
-               return 0;
+               return;
        }
-
        if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
                complete(&se_cmd->cmd_wait_comp);
-               return 1;
+               return;
        }
        list_del(&se_cmd->se_cmd_list);
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
-       return 0;
+       se_cmd->se_tfo->release_cmd(se_cmd);
+}
+
+/* target_put_sess_cmd - Check for active I/O shutdown via kref_put
+ * @se_sess:   session to reference
+ * @se_cmd:    command descriptor to drop
+ */
+int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
+{
+       return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref);
 }
 EXPORT_SYMBOL(target_put_sess_cmd);
 
index cadd4f6e57e15708fc36791dbff0990f0a72bdc5..af088a9e4905db189d9861930d90d0cefeb27b43 100644 (file)
@@ -541,6 +541,7 @@ struct se_cmd {
        struct list_head        se_queue_node;
        struct list_head        se_cmd_list;
        struct completion       cmd_wait_comp;
+       struct kref             cmd_kref;
        struct target_core_fabric_ops *se_tfo;
        int (*execute_task)(struct se_task *);
        void (*transport_complete_callback)(struct se_cmd *);