]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
scsi: target: Fix LUN ref count handling
authorMike Christie <michael.christie@oracle.com>
Sun, 1 Nov 2020 18:59:27 +0000 (12:59 -0600)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 5 Nov 2020 03:39:37 +0000 (22:39 -0500)
Fix two bugs in the LUN refcounting:

 1. For the TCM_WRITE_PROTECTED case we were returning an error after
    taking a ref to the LUN, but never dropping it (caller just send status
    and drops cmd ref).

 2. We still need to do a percpu_ref_tryget_live for the virt LUN 0 like we
    do for other LUNs, because the TPG code does the refcount/wait process
    like it does with other LUNs.

Link: https://lore.kernel.org/r/1604257174-4524-2-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/target/target_core_device.c

index 405d82d4471768beff16669bb1b3865958adeabb..1f673fbc28f932673f2e15407a44e1c1908f6a57 100644 (file)
@@ -65,6 +65,16 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd)
                        atomic_long_add(se_cmd->data_length,
                                        &deve->read_bytes);
 
+               if ((se_cmd->data_direction == DMA_TO_DEVICE) &&
+                   deve->lun_access_ro) {
+                       pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN"
+                               " Access for 0x%08llx\n",
+                               se_cmd->se_tfo->fabric_name,
+                               se_cmd->orig_fe_lun);
+                       rcu_read_unlock();
+                       return TCM_WRITE_PROTECTED;
+               }
+
                se_lun = rcu_dereference(deve->se_lun);
 
                if (!percpu_ref_tryget_live(&se_lun->lun_ref)) {
@@ -76,17 +86,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd)
                se_cmd->pr_res_key = deve->pr_res_key;
                se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
                se_cmd->lun_ref_active = true;
-
-               if ((se_cmd->data_direction == DMA_TO_DEVICE) &&
-                   deve->lun_access_ro) {
-                       pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN"
-                               " Access for 0x%08llx\n",
-                               se_cmd->se_tfo->fabric_name,
-                               se_cmd->orig_fe_lun);
-                       rcu_read_unlock();
-                       ret = TCM_WRITE_PROTECTED;
-                       goto ref_dev;
-               }
        }
 out_unlock:
        rcu_read_unlock();
@@ -106,21 +105,20 @@ out_unlock:
                        return TCM_NON_EXISTENT_LUN;
                }
 
-               se_lun = se_sess->se_tpg->tpg_virt_lun0;
-               se_cmd->se_lun = se_sess->se_tpg->tpg_virt_lun0;
-               se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
-
-               percpu_ref_get(&se_lun->lun_ref);
-               se_cmd->lun_ref_active = true;
-
                /*
                 * Force WRITE PROTECT for virtual LUN 0
                 */
                if ((se_cmd->data_direction != DMA_FROM_DEVICE) &&
-                   (se_cmd->data_direction != DMA_NONE)) {
-                       ret = TCM_WRITE_PROTECTED;
-                       goto ref_dev;
-               }
+                   (se_cmd->data_direction != DMA_NONE))
+                       return TCM_WRITE_PROTECTED;
+
+               se_lun = se_sess->se_tpg->tpg_virt_lun0;
+               if (!percpu_ref_tryget_live(&se_lun->lun_ref))
+                       return TCM_NON_EXISTENT_LUN;
+
+               se_cmd->se_lun = se_sess->se_tpg->tpg_virt_lun0;
+               se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
+               se_cmd->lun_ref_active = true;
        }
        /*
         * RCU reference protected by percpu se_lun->lun_ref taken above that
@@ -128,7 +126,6 @@ out_unlock:
         * pointer can be kfree_rcu() by the final se_lun->lun_group put via
         * target_core_fabric_configfs.c:target_fabric_port_release
         */
-ref_dev:
        se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev);
        atomic_long_inc(&se_cmd->se_dev->num_cmds);