|
Michal Kubecek |
ec8941 |
From d58bb4614c60cb3b6b634ed821f39de22a368665 Mon Sep 17 00:00:00 2001
|
|
Michal Kubecek |
ec8941 |
From: David Disseldorp <ddiss@suse.de>
|
|
Michal Kubecek |
ec8941 |
Date: Fri, 11 Sep 2015 11:57:46 +0200
|
|
Michal Kubecek |
ec8941 |
Subject: [PATCH] target/rbd: SCSI3 check conflict support
|
|
Michal Kubecek |
ec8941 |
Patch-mainline: Not yet, SES2 clustered LIO/RBD
|
|
Michal Kubecek |
ec8941 |
References: fate#318836
|
|
Michal Kubecek |
ec8941 |
|
|
Michal Kubecek |
ec8941 |
Check for existing SCSI3 persistent reservations prior to SCSI command
|
|
Michal Kubecek |
ec8941 |
execution.
|
|
Michal Kubecek |
ec8941 |
|
|
Michal Kubecek |
ec8941 |
Signed-off-by: David Disseldorp <ddiss@suse.de>
|
|
Michal Kubecek |
ec8941 |
---
|
|
Michal Kubecek |
ec8941 |
drivers/target/target_core_rbd.c | 96 +++++++++++++++++++++++++++++++++++++++
|
|
Michal Kubecek |
ec8941 |
1 file changed, 96 insertions(+)
|
|
Michal Kubecek |
ec8941 |
|
|
Michal Kubecek |
ec8941 |
--- a/drivers/target/target_core_rbd.c
|
|
Michal Kubecek |
ec8941 |
+++ b/drivers/target/target_core_rbd.c
|
|
Michal Kubecek |
ec8941 |
@@ -2447,7 +2447,103 @@ tcm_rbd_execute_pr_register_and_move(str
|
|
Michal Kubecek |
ec8941 |
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
|
Michal Kubecek |
ec8941 |
}
|
|
Michal Kubecek |
ec8941 |
|
|
Michal Kubecek |
ec8941 |
+static sense_reason_t
|
|
Michal Kubecek |
ec8941 |
+tcm_rbd_execute_pr_check_scsi3_conflict(struct se_cmd *cmd,
|
|
Michal Kubecek |
ec8941 |
+ struct tcm_rbd_pr_info *pr_info,
|
|
Michal Kubecek |
ec8941 |
+ char *it_nexus)
|
|
Michal Kubecek |
ec8941 |
+{
|
|
Michal Kubecek |
ec8941 |
+ struct tcm_rbd_pr_rsv *rsv;
|
|
Michal Kubecek |
ec8941 |
+ struct tcm_rbd_pr_reg *reg;
|
|
Michal Kubecek |
ec8941 |
+ bool registered_nexus;
|
|
Michal Kubecek |
ec8941 |
+ int rc;
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ if (!pr_info->rsv) {
|
|
Michal Kubecek |
ec8941 |
+ dout("no SCSI3 persistent reservation\n");
|
|
Michal Kubecek |
ec8941 |
+ return TCM_NO_SENSE;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ rsv = pr_info->rsv;
|
|
Michal Kubecek |
ec8941 |
+ dout("PR reservation holder: %s, us: %s\n", rsv->it_nexus, it_nexus);
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ if (!strncmp(rsv->it_nexus, it_nexus, ARRAY_SIZE(rsv->it_nexus))) {
|
|
Michal Kubecek |
ec8941 |
+ dout("cmd is from reservation holder\n");
|
|
Michal Kubecek |
ec8941 |
+ return TCM_NO_SENSE;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ registered_nexus = false;
|
|
Michal Kubecek |
ec8941 |
+ list_for_each_entry(reg, &pr_info->regs, regs_node) {
|
|
Michal Kubecek |
ec8941 |
+ if (!strncmp(reg->it_nexus, it_nexus,
|
|
Michal Kubecek |
ec8941 |
+ ARRAY_SIZE(reg->it_nexus))) {
|
|
Michal Kubecek |
ec8941 |
+ dout("cmd is from PR registrant: %s\n", it_nexus);
|
|
Michal Kubecek |
ec8941 |
+ registered_nexus = true;
|
|
Michal Kubecek |
ec8941 |
+ break;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+ rc = core_scsi3_pr_seq_non_holder(cmd, rsv->type, it_nexus,
|
|
Michal Kubecek |
ec8941 |
+ registered_nexus);
|
|
Michal Kubecek |
ec8941 |
+ if (rc == 1) {
|
|
Michal Kubecek |
ec8941 |
+ dout("SCSI3 reservation conflict\n");
|
|
Michal Kubecek |
ec8941 |
+ return TCM_RESERVATION_CONFLICT;
|
|
Michal Kubecek |
ec8941 |
+ } else if (rc < 0) {
|
|
Michal Kubecek |
ec8941 |
+ pr_warn("SCSI3 PR non-holder check failed\n");
|
|
Michal Kubecek |
ec8941 |
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ return TCM_NO_SENSE;
|
|
Michal Kubecek |
ec8941 |
+}
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+static sense_reason_t
|
|
Michal Kubecek |
ec8941 |
+tcm_rbd_execute_pr_check_conflict(struct se_cmd *cmd,
|
|
Michal Kubecek |
ec8941 |
+ enum target_pr_check_type type)
|
|
Michal Kubecek |
ec8941 |
+{
|
|
Michal Kubecek |
ec8941 |
+ struct se_device *dev = cmd->se_dev;
|
|
Michal Kubecek |
ec8941 |
+ struct tcm_rbd_dev *tcm_rbd_dev = TCM_RBD_DEV(dev);
|
|
Michal Kubecek |
ec8941 |
+ struct tcm_rbd_pr_info *pr_info;
|
|
Michal Kubecek |
ec8941 |
+ char nexus_buf[TCM_RBD_PR_IT_NEXUS_MAXLEN];
|
|
Michal Kubecek |
ec8941 |
+ int rc;
|
|
Michal Kubecek |
ec8941 |
+ sense_reason_t ret;
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ switch (cmd->t_task_cdb[0]) {
|
|
Michal Kubecek |
ec8941 |
+ case INQUIRY:
|
|
Michal Kubecek |
ec8941 |
+ case RELEASE:
|
|
Michal Kubecek |
ec8941 |
+ case RELEASE_10:
|
|
Michal Kubecek |
ec8941 |
+ /* always allow cdb execution */
|
|
Michal Kubecek |
ec8941 |
+ return TCM_NO_SENSE;
|
|
Michal Kubecek |
ec8941 |
+ default:
|
|
Michal Kubecek |
ec8941 |
+ break;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ rc = tcm_rbd_pr_info_get(tcm_rbd_dev, &pr_info, NULL, NULL);
|
|
Michal Kubecek |
ec8941 |
+ if (rc == -ENODATA) {
|
|
Michal Kubecek |
ec8941 |
+ dout("no PR info, can't conflict\n");
|
|
Michal Kubecek |
ec8941 |
+ return TCM_NO_SENSE;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+ if (rc < 0) {
|
|
Michal Kubecek |
ec8941 |
+ /* existing registration required for reservation */
|
|
Michal Kubecek |
ec8941 |
+ pr_err("failed to obtain PR info\n");
|
|
Michal Kubecek |
ec8941 |
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ rc = tcm_rbd_gen_it_nexus(cmd->se_sess, nexus_buf,
|
|
Michal Kubecek |
ec8941 |
+ ARRAY_SIZE(nexus_buf));
|
|
Michal Kubecek |
ec8941 |
+ if (rc < 0) {
|
|
Michal Kubecek |
ec8941 |
+ ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
|
Michal Kubecek |
ec8941 |
+ goto out_info_free;
|
|
Michal Kubecek |
ec8941 |
+ }
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ ret = tcm_rbd_execute_pr_check_scsi3_conflict(cmd, pr_info, nexus_buf);
|
|
Michal Kubecek |
ec8941 |
+ if (ret)
|
|
Michal Kubecek |
ec8941 |
+ goto out_info_free;
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
+ ret = TCM_NO_SENSE;
|
|
Michal Kubecek |
ec8941 |
+out_info_free:
|
|
Michal Kubecek |
ec8941 |
+ kfree(pr_info);
|
|
Michal Kubecek |
ec8941 |
+ return ret;
|
|
Michal Kubecek |
ec8941 |
+}
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
static struct target_pr_ops tcm_rbd_pr_ops = {
|
|
Michal Kubecek |
ec8941 |
+ .check_conflict = tcm_rbd_execute_pr_check_conflict,
|
|
Michal Kubecek |
ec8941 |
+
|
|
Michal Kubecek |
ec8941 |
.pr_read_keys = tcm_rbd_execute_pr_read_keys,
|
|
Michal Kubecek |
ec8941 |
.pr_read_reservation = tcm_rbd_execute_pr_read_reservation,
|
|
Michal Kubecek |
ec8941 |
.pr_report_capabilities = tcm_rbd_execute_pr_report_capabilities,
|