This patch added a function is_passthrough_pr_supportive_dev()
to tell whether the device can support passthrough Persistent
Reservation, if supported, tcmu_configure_device() will set 1 to
dev->passthrough_pr to indicate it.

If dev->passthrough_pr is 1, both dev->transport->pr_ops
and dev->transport->pr_ops->pr_register are not NULL,
core_scsi3_emulate_pro_register() will call
dev->transport->pr_ops->pr_register, this means call
tcmu_execute_pr_register(). It is the same way how
core_scsi3_pri_read_keys() can call tcmu_execute_pr_read_keys.

Signed-off-by: Zhu Lingshan <[email protected]>
---
 drivers/target/target_core_pr.c   | 23 +++++++++++++++++++++++
 drivers/target/target_core_pr.h   |  2 ++
 drivers/target/target_core_user.c | 20 ++++++++++++++++++++
 include/target/target_core_base.h |  7 +++++++
 4 files changed, 52 insertions(+)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 01ac306131c1..0a06b8bb1134 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -2064,6 +2064,21 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 
res_key, u64 sa_res_key,
        sense_reason_t ret = TCM_NO_SENSE;
        int pr_holder = 0, type;
 
+       if (dev->transport->pr_ops && dev->transport->pr_ops->pr_register
+           && dev->passthrough_pr) {
+               bool ignore_existing;
+
+               if (register_type == REGISTER_AND_IGNORE_EXISTING_KEY)
+                       ignore_existing = true;
+               else
+                       ignore_existing = false;
+               ret = dev->transport->pr_ops->pr_register(cmd, res_key,
+                                                         sa_res_key, aptpl,
+                                                         all_tg_pt, spec_i_pt,
+                                                         ignore_existing);
+               return ret;
+       }
+
        if (!se_sess || !se_lun) {
                pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -3707,6 +3722,7 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd)
        struct t10_pr_registration *pr_reg;
        unsigned char *buf;
        u32 add_len = 0, off = 8;
+       sense_reason_t ret = 0;
 
        if (cmd->data_length < 8) {
                pr_err("PRIN SA READ_KEYS SCSI Data Length: %u"
@@ -3718,6 +3734,13 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd)
        if (!buf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
+       if (dev->transport->pr_ops && dev->transport->pr_ops->pr_read_keys
+           && dev->passthrough_pr) {
+               ret = dev->transport->pr_ops->pr_read_keys(cmd, buf,
+                                                          cmd->data_length);
+               return ret;
+       }
+
        put_unaligned_be32(dev->t10_pr.pr_generation, buf);
 
        spin_lock(&dev->t10_pr.registration_lock);
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
index 198fad5c89dc..1a74112c35d3 100644
--- a/drivers/target/target_core_pr.h
+++ b/drivers/target/target_core_pr.h
@@ -49,6 +49,8 @@
 #define PR_APTPL_MAX_IPORT_LEN                 256
 #define PR_APTPL_MAX_TPORT_LEN                 256
 
+#define PASSTHROUGH_PR_SUPPORT                 1
+
 /*
  *  Function defined in target_core_spc.c
  */
diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index ea3685106d35..bde325888477 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2955,6 +2955,21 @@ tcmu_execute_pr_read_keys(struct se_cmd *cmd, unsigned 
char *buf, u32 buf_len)
        return TCM_NO_SENSE;
 }
 
+/*
+ * This function can help to check wheterh the device support
+ * pass through PR operations. Now only Ceph RBD support
+ * passthrough PR. When someday we have another kind of
+ * device can support passthrough PR, we can easily add
+ * a line like ret |= !strncmp(udev->dev_config, "qcow/", 5);
+ */
+static int is_passthrough_pr_supportive_dev(struct tcmu_dev *udev)
+{
+       int ret = 0;
+
+       ret |= !strncmp(udev->dev_config, "rbd/", 4);
+       return ret;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
        struct tcmu_dev *udev = TCMU_DEV(dev);
@@ -3046,6 +3061,11 @@ static int tcmu_configure_device(struct se_device *dev)
        list_add(&udev->node, &root_udev);
        mutex_unlock(&root_udev_mutex);
 
+       if (is_passthrough_pr_supportive_dev(udev) && dev->transport->pr_ops) {
+               mutex_init(&udev->pr_info.pr_info_lock);
+               dev->passthrough_pr = PASSTHROUGH_PR_SUPPORT;
+       }
+
        return 0;
 
 err_netlink:
diff --git a/include/target/target_core_base.h 
b/include/target/target_core_base.h
index 9f9f5902af38..9acb3363fd2b 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -825,6 +825,13 @@ struct se_device {
        /* For se_lun->lun_se_dev RCU read-side critical access */
        u32                     hba_index;
        struct rcu_head         rcu_head;
+       /*
+        * For now, only Ceph RBD support pass through PR operations,
+        * others like QCOW can not support this yet, so we need this
+        * int to indicate whether we can send pass through PR message
+        * to userspace.
+        */
+       int passthrough_pr;
 };
 
 struct se_hba {
-- 
2.17.1

Reply via email to