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;