Blob Blame History Raw
From b63477dcf778d337140a00553417daf8b4a1f01a Mon Sep 17 00:00:00 2001
From: David Disseldorp <ddiss@suse.de>
Date: Thu, 3 Sep 2015 19:27:21 +0200
Subject: [PATCH] target/rbd: add SCSI2 reservation entry to PR info
Patch-mainline: Not yet, SES2 clustered LIO/RBD
References: fate#318836

Track SCSI2 reservation status alongside persistent reservation state,
so that it can piggy back on the existing transactional xattr update
functionality.

Signed-off-by: David Disseldorp <ddiss@suse.de>
---
 drivers/target/target_core_rbd.c |  158 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 147 insertions(+), 11 deletions(-)

--- a/drivers/target/target_core_rbd.c
+++ b/drivers/target/target_core_rbd.c
@@ -685,12 +685,14 @@ static bool tcm_rbd_get_write_cache(stru
 
 #define TCM_RBD_PR_INFO_XATTR_FIELD_VER		0
 #define TCM_RBD_PR_INFO_XATTR_FIELD_SEQ		1
-#define TCM_RBD_PR_INFO_XATTR_FIELD_GEN		2
-#define TCM_RBD_PR_INFO_XATTR_FIELD_SCSI3_RSV	3
-#define TCM_RBD_PR_INFO_XATTR_FIELD_NUM_REGS	4
-#define TCM_RBD_PR_INFO_XATTR_FIELD_REGS_START	5
+#define TCM_RBD_PR_INFO_XATTR_FIELD_SCSI2_RSV	2
+#define TCM_RBD_PR_INFO_XATTR_FIELD_GEN		3
+#define TCM_RBD_PR_INFO_XATTR_FIELD_SCSI3_RSV	4
+#define TCM_RBD_PR_INFO_XATTR_FIELD_NUM_REGS	5
+#define TCM_RBD_PR_INFO_XATTR_FIELD_REGS_START	6
 
 #define TCM_RBD_PR_INFO_XATTR_VAL_SCSI3_RSV_ABSENT	"No SPC-3 Reservation holder"
+#define TCM_RBD_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT	"No SPC-2 Reservation holder"
 
 /* don't allow encoded PR info to exceed 8K */
 #define TCM_RBD_PR_INFO_XATTR_MAX_SIZE 8192
@@ -734,9 +736,19 @@ struct tcm_rbd_pr_reg {
 	((sizeof("0x") + sizeof(u64) * 2) + sizeof(" ") +	\
 	 TCM_RBD_PR_IT_NEXUS_MAXLEN + sizeof("\n"))
 
+struct tcm_rbd_scsi2_rsv {
+	/*
+	 * I-T nexus for SCSI2 (RESERVE/RELEASE) reservation.
+	 */
+	char it_nexus[TCM_RBD_PR_IT_NEXUS_MAXLEN];
+};
+#define TCM_RBD_PR_INFO_XATTR_ENCODED_SCSI2_RSV_MAXLEN		\
+	(TCM_RBD_PR_IT_NEXUS_MAXLEN + sizeof("\n"))
+
 struct tcm_rbd_pr_info {
 	u32 vers;		/* on disk format version number */
 	u32 seq; 		/* sequence number bumped every xattr write */
+	struct tcm_rbd_scsi2_rsv *scsi2_rsv; /* SCSI2 reservation if any */
 	u32 gen; 		/* PR generation number */
 	struct tcm_rbd_pr_rsv *rsv;	/* SCSI3 reservation if any */
 	u32 num_regs;		/* number of registrations */
@@ -745,6 +757,7 @@ struct tcm_rbd_pr_info {
 #define TCM_RBD_PR_INFO_XATTR_ENCODED_MAXLEN(_num_regs)			\
 	((sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") +		\
 	 (sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") +		\
+	 TCM_RBD_PR_INFO_XATTR_ENCODED_SCSI2_RSV_MAXLEN + 		\
 	 (sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") +		\
 	 TCM_RBD_PR_INFO_XATTR_ENCODED_PR_RSV_MAXLEN +	 		\
 	 (sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") +		\
@@ -787,6 +800,7 @@ tcm_rbd_pr_info_free(struct tcm_rbd_pr_i
 	struct tcm_rbd_pr_reg *reg;
 	struct tcm_rbd_pr_reg *reg_n;
 
+	kfree(pr_info->scsi2_rsv);
 	kfree(pr_info->rsv);
 	list_for_each_entry_safe(reg, reg_n, &pr_info->regs, regs_node) {
 		kfree(reg);
@@ -917,6 +931,38 @@ tcm_rbd_pr_info_unregister_reg(struct tc
 }
 
 static int
+tcm_rbd_pr_info_scsi2_rsv_set(struct tcm_rbd_pr_info *pr_info, char *nexus)
+{
+	struct tcm_rbd_scsi2_rsv *scsi2_rsv;
+
+	if (pr_info->scsi2_rsv != NULL) {
+		pr_err("rsv_set called with existing SCSI2 reservation\n");
+		return -EINVAL;
+	}
+
+	scsi2_rsv = kmalloc(sizeof(*scsi2_rsv), GFP_KERNEL);
+	if (!scsi2_rsv) {
+		return -ENOMEM;
+	}
+
+	strlcpy(scsi2_rsv->it_nexus, nexus, ARRAY_SIZE(scsi2_rsv->it_nexus));
+
+	pr_info->scsi2_rsv = scsi2_rsv;
+
+	dout("pr_info scsi2_rsv set: %s\n", nexus);
+
+	return 0;
+}
+
+static void
+tcm_rbd_pr_info_scsi2_rsv_clear(struct tcm_rbd_pr_info *pr_info)
+{
+	dout("pr_info scsi2_rsv clearing: %s\n", pr_info->scsi2_rsv->it_nexus);
+	kfree(pr_info->scsi2_rsv);
+	pr_info->scsi2_rsv = NULL;
+}
+
+static int
 tcm_rbd_pr_info_vers_decode(char *str, u32 *vers)
 {
 	int rc;
@@ -954,6 +1000,37 @@ tcm_rbd_pr_info_seq_decode(char *str, u3
 }
 
 static int
+tcm_rbd_pr_info_scsi2_rsv_decode(char *str,
+				 struct tcm_rbd_scsi2_rsv **_scsi2_rsv)
+{
+	struct tcm_rbd_scsi2_rsv *scsi2_rsv;
+
+	BUG_ON(!_scsi2_rsv);
+	if (!strncmp(str, TCM_RBD_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT,
+		     sizeof(TCM_RBD_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT))) {
+		scsi2_rsv = NULL;
+	} else {
+		size_t n;
+
+		scsi2_rsv = kzalloc(sizeof(*scsi2_rsv), GFP_KERNEL);
+		if (!scsi2_rsv) {
+			return -ENOMEM;
+		}
+
+		n = strlcpy(scsi2_rsv->it_nexus, str,
+			    TCM_RBD_PR_IT_NEXUS_MAXLEN);
+		if (n >= TCM_RBD_PR_IT_NEXUS_MAXLEN) {
+			kfree(scsi2_rsv);
+			return -EINVAL;
+		}
+	}
+
+	dout("processed pr_info SCSI2 rsv: %s\n", str);
+	*_scsi2_rsv = scsi2_rsv;
+	return 0;
+}
+
+static int
 tcm_rbd_pr_info_gen_decode(char *str, u32 *gen)
 {
 	int rc;
@@ -1092,6 +1169,12 @@ tcm_rbd_pr_info_decode(char *pr_xattr,
 			if (rc < 0) {
 				goto err_info_free;
 			}
+		} else if (field == TCM_RBD_PR_INFO_XATTR_FIELD_SCSI2_RSV) {
+			rc = tcm_rbd_pr_info_scsi2_rsv_decode(str,
+							&pr_info->scsi2_rsv);
+			if (rc < 0) {
+				goto err_info_free;
+			}
 		} else if (field == TCM_RBD_PR_INFO_XATTR_FIELD_GEN) {
 			rc = tcm_rbd_pr_info_gen_decode(str, &pr_info->gen);
 			if (rc < 0) {
@@ -1147,15 +1230,49 @@ err_info_free:
 }
 
 static int
-tcm_rbd_pr_info_vers_seq_gen_encode(char *buf, size_t buf_remain, u32 vers,
-				    u32 seq, u32 gen)
+tcm_rbd_pr_info_vers_seq_encode(char *buf, size_t buf_remain, u32 vers, u32 seq)
+{
+	int rc;
+
+	rc = snprintf(buf, buf_remain, "0x%08x\n0x%08x\n",
+		      vers, seq);
+	if ((rc < 0) || (rc >= buf_remain)) {
+		pr_err("failed to encode PR vers and seq\n");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int
+tcm_rbd_pr_info_scsi2_rsv_encode(char *buf, size_t buf_remain,
+				 struct tcm_rbd_scsi2_rsv *scsi2_rsv)
 {
 	int rc;
 
-	rc = snprintf(buf, buf_remain, "0x%08x\n0x%08x\n0x%08x\n",
-		      vers, seq, gen);
+	if (!scsi2_rsv) {
+		/* no reservation */
+		rc = snprintf(buf, buf_remain, "%s\n",
+			      TCM_RBD_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT);
+	} else {
+		rc = snprintf(buf, buf_remain, "%s\n", scsi2_rsv->it_nexus);
+	}
 	if ((rc < 0) || (rc >= buf_remain)) {
-		pr_err("failed to encode PR vers, seq and gen\n");
+		pr_err("failed to encode SCSI2 reservation\n");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int
+tcm_rbd_pr_info_gen_encode(char *buf, size_t buf_remain, u32 gen)
+{
+	int rc;
+
+	rc = snprintf(buf, buf_remain, "0x%08x\n", gen);
+	if ((rc < 0) || (rc >= buf_remain)) {
+		pr_err("failed to encode PR gen\n");
 		return -EINVAL;
 	}
 
@@ -1246,8 +1363,27 @@ tcm_rbd_pr_info_encode(struct tcm_rbd_pr
 	}
 
 	p = pr_xattr;
-	rc = tcm_rbd_pr_info_vers_seq_gen_encode(p, buf_remain, pr_info->vers,
-						 pr_info->seq, pr_info->gen);
+	rc = tcm_rbd_pr_info_vers_seq_encode(p, buf_remain, pr_info->vers,
+					     pr_info->seq);
+	if (rc < 0) {
+		rc = -EINVAL;
+		goto err_xattr_free;
+	}
+
+	p += rc;
+	buf_remain -= rc;
+
+	rc = tcm_rbd_pr_info_scsi2_rsv_encode(p, buf_remain,
+					      pr_info->scsi2_rsv);
+	 if (rc < 0) {
+		rc = -EINVAL;
+		goto err_xattr_free;
+	}
+
+	p += rc;
+	buf_remain -= rc;
+
+	rc = tcm_rbd_pr_info_gen_encode(p, buf_remain, pr_info->gen);
 	if (rc < 0) {
 		rc = -EINVAL;
 		goto err_xattr_free;