Blob Blame History Raw
From 51c0b8016fa80b7ab94235b9fac994e7f9bae9fe Mon Sep 17 00:00:00 2001
From: David Disseldorp <ddiss@suse.de>
Date: Wed, 7 Dec 2016 02:20:49 +0100
Subject: [PATCH] target: fix tcm_rbd_gen_it_nexus for emulated XCOPY state
Patch-mainline: Not yet, SES clustered LIO/RBD
References: bsc#1003606

An emulated command structure is initialised prior to dispatching
read/write I/O for the XCOPY job to the LIO backstore layer.

Prior to 4416f89b8cfcb794d040fc3b68e5fb159b7d8d02, this was handled with
the following sequence:

target_xcopy_read_source()
target_xcopy_write_destination()
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length, ...)
                se_cmd->se_sess = NULL
        target_xcopy_setup_pt_cmd(struct xcopy_pt_cmd *xpt_cmd,...)
                struct se_cmd *cmd = &xpt_cmd->se_cmd;
                target_setup_cmd_from_cdb(cmd)
                        ret = target_check_reservation(cmd);
                                if (!cmd->se_sess)
                                        return 0;

The emulated command structure was initialised with a session pointer
set to NULL, which caused the persistent reservation check to be
skipped.

Following 4416f89b8cfcb794d040fc3b68e5fb159b7d8d02, the XCOPY emulated
command structure includes an emulated session structure, which sees the
following chain:
target_xcopy_read_source()
target_xcopy_write_destination()
        transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess,
			      length, ...)
                se_cmd->se_tfo = xcopy_pt_tfo
                se_cmd->se_sess = xcopy_pt_sess
        target_xcopy_issue_pt_cmd()
                transport_generic_new_cmd(se_cmd)
                target_execute_cmd(se_cmd);
                        __target_execute_cmd()
                        ...
                                ret = target_check_reservation(cmd);
                                     tcm_rbd_execute_pr_check_conflict()
						tcm_rbd_gen_it_nexus()

With the session pointer non-null, the persistent reservation check is
not skipped. Instead, it proceeds using the emulated session and fabric
structures used for the xcopy job. This trips a NULL pointer callback in
tcm_rbd_gen_it_nexus(), which it expects a non-null fabric callback.

Signed-off-by: David Disseldorp <ddiss@suse.de>
Reviewed-by: Jan Fajerski <jan.fajerski@suse.com>
---
 drivers/target/target_core_rbd.c |   22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

--- a/drivers/target/target_core_rbd.c
+++ b/drivers/target/target_core_rbd.c
@@ -785,9 +785,12 @@ tcm_rbd_gen_it_nexus(struct se_session *
 {
 	struct se_portal_group *se_tpg;
 	const struct target_core_fabric_ops *tfo;
+	u32 tpg_tag = 0;
+	char *tpg_wwn = "";
 	int rc;
 
-	if (!se_sess || !se_sess->se_node_acl || !se_sess->se_tpg) {
+	if (!se_sess || !se_sess->se_node_acl || !se_sess->se_tpg
+					|| !se_sess->se_tpg->se_tpg_tfo) {
 		pr_warn("invalid session for IT nexus generation\n");
 		return -EINVAL;
 	}
@@ -795,16 +798,29 @@ tcm_rbd_gen_it_nexus(struct se_session *
 	se_tpg = se_sess->se_tpg;
 	tfo = se_tpg->se_tpg_tfo;
 
+	/*
+	 * nexus generation may be coming from an xcopy, in which case tfo
+	 * refers to xcopy_pt_tfo (tpg_get_wwn and tpg_get_tag are NULL).
+	 */
+	if (tfo->tpg_get_tag) {
+		tpg_tag = tfo->tpg_get_tag(se_tpg);
+	}
+	if (tfo->tpg_get_wwn) {
+		tpg_wwn = tfo->tpg_get_wwn(se_tpg);
+	}
+
 	rc = snprintf(nexus_buf, buflen, "%s,i,0x%llx,%s,t,0x%x",
 		      se_sess->se_node_acl->initiatorname,
 		      se_sess->sess_bin_isid,
-		      tfo->tpg_get_wwn(se_tpg),
-		      (u32)tfo->tpg_get_tag(se_tpg));
+		      tpg_wwn,
+		      tpg_tag);
 	if ((rc < 0) || (rc >= buflen)) {
 		pr_err("error formatting reserve cookie\n");
 		return -EINVAL;
 	}
 
+	pr_debug("generated nexus: %s\n", nexus_buf);
+
 	return 0;
 }