]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
scsi: target: Clear cmd_cnt when initial counter enrollment fails
authorLeon Romanovsky <leonro@nvidia.com>
Wed, 22 Jul 2026 06:30:10 +0000 (09:30 +0300)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 29 Jul 2026 01:52:09 +0000 (21:52 -0400)
When target_get_sess_cmd() fails during session shutdown because
percpu_ref_tryget_live() returns false, the command keeps the
se_cmd->cmd_cnt pointer that __target_init_cmd() assigned earlier
without owning a reference. Final release through
target_release_cmd_kref() then issues an unmatched percpu_ref_put().

Commit 8e288be8606a ("scsi: target: Pass in cmd counter to use during
cmd setup") moved the cmd_cnt assignment ahead of the reference
acquisition.  Clear se_cmd->cmd_cnt whenever the initial
target_get_sess_cmd() fails in target_init_cmd() and
target_submit_tmr(), so release performs exactly one matching put per
acquired reference.

Fixes: 8e288be8606a ("scsi: target: Pass in cmd counter to use during cmd setup")
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Link: https://patch.msgid.link/20260722-reference-count-underflow-in-target-v1-1-63ab664f12fd@nvidia.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/target/target_core_transport.c

index fad03a15c969e6d74ad628ae5f10b7f52017fc39..dcfe945949167d2d6e07bcb6026cc9bae9375190 100644 (file)
@@ -1734,6 +1734,7 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
                    u32 data_length, int task_attr, int data_dir, int flags)
 {
        struct se_portal_group *se_tpg;
+       int ret;
 
        se_tpg = se_sess->se_tpg;
        BUG_ON(!se_tpg);
@@ -1763,7 +1764,11 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
         * necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second
         * kref_put() to happen during fabric packet acknowledgement.
         */
-       return target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+       ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+       if (ret)
+               se_cmd->cmd_cnt = NULL;
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(target_init_cmd);
 
@@ -2039,8 +2044,10 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
         * allocation failure.
         */
        ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, gfp);
-       if (ret < 0)
+       if (ret < 0) {
+               se_cmd->cmd_cnt = NULL;
                return -ENOMEM;
+       }
 
        if (tm_type == TMR_ABORT_TASK)
                se_cmd->se_tmr_req->ref_task_tag = tag;
@@ -2048,6 +2055,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
        /* See target_submit_cmd for commentary */
        ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
        if (ret) {
+               se_cmd->cmd_cnt = NULL;
                core_tmr_release_req(se_cmd->se_tmr_req);
                return ret;
        }