]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.9
authorSasha Levin <sashal@kernel.org>
Wed, 13 Jan 2021 16:06:39 +0000 (11:06 -0500)
committerSasha Levin <sashal@kernel.org>
Wed, 13 Jan 2021 16:06:39 +0000 (11:06 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.9/scsi-target-fix-xcopy-naa-identifier-lookup.patch [new file with mode: 0644]
queue-4.9/series [new file with mode: 0644]
queue-4.9/target-add-xcopy-target-segment-desc-sense-codes.patch [new file with mode: 0644]
queue-4.9/target-bounds-check-xcopy-segment-descriptor-list.patch [new file with mode: 0644]
queue-4.9/target-simplify-xcopy-wwn-se_dev-lookup-helper.patch [new file with mode: 0644]
queue-4.9/target-use-xcopy-segment-descriptor-cscd-ids.patch [new file with mode: 0644]
queue-4.9/xcopy-loop-over-devices-using-idr-helper.patch [new file with mode: 0644]

diff --git a/queue-4.9/scsi-target-fix-xcopy-naa-identifier-lookup.patch b/queue-4.9/scsi-target-fix-xcopy-naa-identifier-lookup.patch
new file mode 100644 (file)
index 0000000..9a09b5e
--- /dev/null
@@ -0,0 +1,214 @@
+From 9f776d16f2d5fb4baa90b4d46a62022b2e368c23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Nov 2020 02:21:58 +0100
+Subject: scsi: target: Fix XCOPY NAA identifier lookup
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ Upstream commit 2896c93811e39d63a4d9b63ccf12a8fbc226e5e4 ]
+
+When attempting to match EXTENDED COPY CSCD descriptors with corresponding
+se_devices, target_xcopy_locate_se_dev_e4() currently iterates over LIO's
+global devices list which includes all configured backstores.
+
+This change ensures that only initiator-accessible backstores are
+considered during CSCD descriptor lookup, according to the session's
+se_node_acl LUN list.
+
+To avoid LUN removal race conditions, device pinning is changed from being
+configfs based to instead using the se_node_acl lun_ref.
+
+Reference: CVE-2020-28374
+Fixes: cbf031f425fd ("target: Add support for EXTENDED_COPY copy offload emulation")
+Reviewed-by: Lee Duncan <lduncan@suse.com>
+Signed-off-by: David Disseldorp <ddiss@suse.de>
+Signed-off-by: Mike Christie <michael.christie@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/target_core_xcopy.c | 119 +++++++++++++++++------------
+ drivers/target/target_core_xcopy.h |   1 +
+ 2 files changed, 71 insertions(+), 49 deletions(-)
+
+diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
+index 065669f9ca8cc..84e3bf1132fd5 100644
+--- a/drivers/target/target_core_xcopy.c
++++ b/drivers/target/target_core_xcopy.c
+@@ -52,60 +52,83 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
+       return 0;
+ }
+-struct xcopy_dev_search_info {
+-      const unsigned char *dev_wwn;
+-      struct se_device *found_dev;
+-};
+-
++/**
++ * target_xcopy_locate_se_dev_e4_iter - compare XCOPY NAA device identifiers
++ *
++ * @se_dev: device being considered for match
++ * @dev_wwn: XCOPY requested NAA dev_wwn
++ * @return: 1 on match, 0 on no-match
++ */
+ static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
+-                                            void *data)
++                                            const unsigned char *dev_wwn)
+ {
+-      struct xcopy_dev_search_info *info = data;
+       unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+       int rc;
+-      if (!se_dev->dev_attrib.emulate_3pc)
++      if (!se_dev->dev_attrib.emulate_3pc) {
++              pr_debug("XCOPY: emulate_3pc disabled on se_dev %p\n", se_dev);
+               return 0;
++      }
+       memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
+       target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
+-      rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
+-      if (rc != 0)
+-              return 0;
+-
+-      info->found_dev = se_dev;
+-      pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
+-
+-      rc = target_depend_item(&se_dev->dev_group.cg_item);
++      rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
+       if (rc != 0) {
+-              pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n",
+-                     rc, se_dev);
+-              return rc;
++              pr_debug("XCOPY: skip non-matching: %*ph\n",
++                       XCOPY_NAA_IEEE_REGEX_LEN, tmp_dev_wwn);
++              return 0;
+       }
++      pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
+-      pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n",
+-               se_dev, &se_dev->dev_group);
+       return 1;
+ }
+-static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
+-                                      struct se_device **found_dev)
++static int target_xcopy_locate_se_dev_e4(struct se_session *sess,
++                                      const unsigned char *dev_wwn,
++                                      struct se_device **_found_dev,
++                                      struct percpu_ref **_found_lun_ref)
+ {
+-      struct xcopy_dev_search_info info;
+-      int ret;
+-
+-      memset(&info, 0, sizeof(info));
+-      info.dev_wwn = dev_wwn;
+-
+-      ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info);
+-      if (ret == 1) {
+-              *found_dev = info.found_dev;
+-              return 0;
+-      } else {
+-              pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+-              return -EINVAL;
++      struct se_dev_entry *deve;
++      struct se_node_acl *nacl;
++      struct se_lun *this_lun = NULL;
++      struct se_device *found_dev = NULL;
++
++      /* cmd with NULL sess indicates no associated $FABRIC_MOD */
++      if (!sess)
++              goto err_out;
++
++      pr_debug("XCOPY 0xe4: searching for: %*ph\n",
++               XCOPY_NAA_IEEE_REGEX_LEN, dev_wwn);
++
++      nacl = sess->se_node_acl;
++      rcu_read_lock();
++      hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) {
++              struct se_device *this_dev;
++              int rc;
++
++              this_lun = rcu_dereference(deve->se_lun);
++              this_dev = rcu_dereference_raw(this_lun->lun_se_dev);
++
++              rc = target_xcopy_locate_se_dev_e4_iter(this_dev, dev_wwn);
++              if (rc) {
++                      if (percpu_ref_tryget_live(&this_lun->lun_ref))
++                              found_dev = this_dev;
++                      break;
++              }
+       }
++      rcu_read_unlock();
++      if (found_dev == NULL)
++              goto err_out;
++
++      pr_debug("lun_ref held for se_dev: %p se_dev->se_dev_group: %p\n",
++               found_dev, &found_dev->dev_group);
++      *_found_dev = found_dev;
++      *_found_lun_ref = &this_lun->lun_ref;
++      return 0;
++err_out:
++      pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
++      return -EINVAL;
+ }
+ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
+@@ -248,12 +271,16 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
+       switch (xop->op_origin) {
+       case XCOL_SOURCE_RECV_OP:
+-              rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
+-                                              &xop->dst_dev);
++              rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
++                                              xop->dst_tid_wwn,
++                                              &xop->dst_dev,
++                                              &xop->remote_lun_ref);
+               break;
+       case XCOL_DEST_RECV_OP:
+-              rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
+-                                              &xop->src_dev);
++              rc = target_xcopy_locate_se_dev_e4(se_cmd->se_sess,
++                                              xop->src_tid_wwn,
++                                              &xop->src_dev,
++                                              &xop->remote_lun_ref);
+               break;
+       default:
+               pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
+@@ -397,18 +424,12 @@ static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd)
+ static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
+ {
+-      struct se_device *remote_dev;
+-
+       if (xop->op_origin == XCOL_SOURCE_RECV_OP)
+-              remote_dev = xop->dst_dev;
++              pr_debug("putting dst lun_ref for %p\n", xop->dst_dev);
+       else
+-              remote_dev = xop->src_dev;
+-
+-      pr_debug("Calling configfs_undepend_item for"
+-                " remote_dev: %p remote_dev->dev_group: %p\n",
+-                remote_dev, &remote_dev->dev_group.cg_item);
++              pr_debug("putting src lun_ref for %p\n", xop->src_dev);
+-      target_undepend_item(&remote_dev->dev_group.cg_item);
++      percpu_ref_put(xop->remote_lun_ref);
+ }
+ static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
+diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h
+index 700a981c7b415..7db8d0c9223f8 100644
+--- a/drivers/target/target_core_xcopy.h
++++ b/drivers/target/target_core_xcopy.h
+@@ -19,6 +19,7 @@ struct xcopy_op {
+       struct se_device *dst_dev;
+       unsigned char dst_tid_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+       unsigned char local_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
++      struct percpu_ref *remote_lun_ref;
+       sector_t src_lba;
+       sector_t dst_lba;
+-- 
+2.27.0
+
diff --git a/queue-4.9/series b/queue-4.9/series
new file mode 100644 (file)
index 0000000..4a7bc21
--- /dev/null
@@ -0,0 +1,6 @@
+target-bounds-check-xcopy-segment-descriptor-list.patch
+target-simplify-xcopy-wwn-se_dev-lookup-helper.patch
+target-use-xcopy-segment-descriptor-cscd-ids.patch
+xcopy-loop-over-devices-using-idr-helper.patch
+scsi-target-fix-xcopy-naa-identifier-lookup.patch
+target-add-xcopy-target-segment-desc-sense-codes.patch
diff --git a/queue-4.9/target-add-xcopy-target-segment-desc-sense-codes.patch b/queue-4.9/target-add-xcopy-target-segment-desc-sense-codes.patch
new file mode 100644 (file)
index 0000000..35c6cb3
--- /dev/null
@@ -0,0 +1,81 @@
+From 5887c3bb2692b2cfefe822609206034c7587adae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Dec 2016 11:37:53 +0100
+Subject: target: add XCOPY target/segment desc sense codes
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ Upstream commit e864212078ded276bdb272b2e0ee6a979357ca8a ]
+
+As defined in http://www.t10.org/lists/asc-num.htm. To be used during
+validation of XCOPY target and segment descriptor lists.
+
+Signed-off-by: David Disseldorp <ddiss@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/target_core_transport.c | 24 ++++++++++++++++++++++++
+ include/target/target_core_base.h      |  4 ++++
+ 2 files changed, 28 insertions(+)
+
+diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
+index e738b4621cbba..ecd707f74ddcb 100644
+--- a/drivers/target/target_core_transport.c
++++ b/drivers/target/target_core_transport.c
+@@ -1736,6 +1736,10 @@ void transport_generic_request_failure(struct se_cmd *cmd,
+       case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
+       case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
+       case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
++      case TCM_TOO_MANY_TARGET_DESCS:
++      case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE:
++      case TCM_TOO_MANY_SEGMENT_DESCS:
++      case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE:
+               break;
+       case TCM_OUT_OF_RESOURCES:
+               sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+@@ -2886,6 +2890,26 @@ static const struct sense_info sense_info_table[] = {
+               .key = ILLEGAL_REQUEST,
+               .asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */
+       },
++      [TCM_TOO_MANY_TARGET_DESCS] = {
++              .key = ILLEGAL_REQUEST,
++              .asc = 0x26,
++              .ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */
++      },
++      [TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = {
++              .key = ILLEGAL_REQUEST,
++              .asc = 0x26,
++              .ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */
++      },
++      [TCM_TOO_MANY_SEGMENT_DESCS] = {
++              .key = ILLEGAL_REQUEST,
++              .asc = 0x26,
++              .ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */
++      },
++      [TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = {
++              .key = ILLEGAL_REQUEST,
++              .asc = 0x26,
++              .ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */
++      },
+       [TCM_PARAMETER_LIST_LENGTH_ERROR] = {
+               .key = ILLEGAL_REQUEST,
+               .asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */
+diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
+index 30f99ce4c6cea..8a70d38f13329 100644
+--- a/include/target/target_core_base.h
++++ b/include/target/target_core_base.h
+@@ -178,6 +178,10 @@ enum tcm_sense_reason_table {
+       TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED  = R(0x16),
+       TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED  = R(0x17),
+       TCM_COPY_TARGET_DEVICE_NOT_REACHABLE    = R(0x18),
++      TCM_TOO_MANY_TARGET_DESCS               = R(0x19),
++      TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE   = R(0x1a),
++      TCM_TOO_MANY_SEGMENT_DESCS              = R(0x1b),
++      TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE  = R(0x1c),
+ #undef R
+ };
+-- 
+2.27.0
+
diff --git a/queue-4.9/target-bounds-check-xcopy-segment-descriptor-list.patch b/queue-4.9/target-bounds-check-xcopy-segment-descriptor-list.patch
new file mode 100644 (file)
index 0000000..9a3cc0c
--- /dev/null
@@ -0,0 +1,75 @@
+From adf9c800af3f75436ccf88870c4a08168150f32f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Dec 2016 11:37:55 +0100
+Subject: target: bounds check XCOPY segment descriptor list
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ Upstream commit af9f62c1686268c0517b289274d38f3a03bebd2a ]
+
+Check the length of the XCOPY request segment descriptor list against
+the value advertised via the MAXIMUM SEGMENT DESCRIPTOR COUNT field in
+the RECEIVE COPY OPERATING PARAMETERS response.
+
+spc4r37 6.4.3.5 states:
+  If the number of segment descriptors exceeds the allowed number, the
+  copy manager shall terminate the command with CHECK CONDITION status,
+  with the sense key set to ILLEGAL REQUEST, and the additional sense
+  code set to TOO MANY SEGMENT DESCRIPTORS.
+
+This functionality is testable using the libiscsi
+ExtendedCopy.DescrLimits test.
+
+Signed-off-by: David Disseldorp <ddiss@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/target_core_xcopy.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
+index 18848ba8d2ba0..a63b2fff82cc6 100644
+--- a/drivers/target/target_core_xcopy.c
++++ b/drivers/target/target_core_xcopy.c
+@@ -305,17 +305,26 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
+ static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
+                               struct xcopy_op *xop, unsigned char *p,
+-                              unsigned int sdll)
++                              unsigned int sdll, sense_reason_t *sense_ret)
+ {
+       unsigned char *desc = p;
+       unsigned int start = 0;
+       int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
++      *sense_ret = TCM_INVALID_PARAMETER_LIST;
++
+       if (offset != 0) {
+               pr_err("XCOPY segment descriptor list length is not"
+                       " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
+               return -EINVAL;
+       }
++      if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
++              pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
++                      " large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
++              /* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
++              *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
++              return -EINVAL;
++      }
+       while (start < sdll) {
+               /*
+@@ -913,7 +922,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+       seg_desc = &p[16];
+       seg_desc += (rc * XCOPY_TARGET_DESC_LEN);
+-      rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll);
++      rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
++                                                  sdll, &ret);
+       if (rc <= 0) {
+               xcopy_pt_undepend_remotedev(xop);
+               goto out;
+-- 
+2.27.0
+
diff --git a/queue-4.9/target-simplify-xcopy-wwn-se_dev-lookup-helper.patch b/queue-4.9/target-simplify-xcopy-wwn-se_dev-lookup-helper.patch
new file mode 100644 (file)
index 0000000..6cbcb3d
--- /dev/null
@@ -0,0 +1,82 @@
+From 8ba1f6ed91d4efddebfc3f081e239cf51d3f68ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Jan 2017 18:04:05 +0100
+Subject: target: simplify XCOPY wwn->se_dev lookup helper
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ Upstream commit 94aae4caacda89a1bdb7198b260f4ca3595b7ed7 ]
+
+target_xcopy_locate_se_dev_e4() is used to locate an se_dev, based on
+the WWN provided with the XCOPY request. Remove a couple of unneeded
+arguments, and rely on the caller for the src/dst test.
+
+Signed-off-by: David Disseldorp <ddiss@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/target_core_xcopy.c | 28 +++++++++-------------------
+ 1 file changed, 9 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
+index a63b2fff82cc6..c4bd86976e450 100644
+--- a/drivers/target/target_core_xcopy.c
++++ b/drivers/target/target_core_xcopy.c
+@@ -52,18 +52,13 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
+       return 0;
+ }
+-static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
+-                                      bool src)
++static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
++                                      struct se_device **found_dev)
+ {
+       struct se_device *se_dev;
+-      unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
++      unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+       int rc;
+-      if (src)
+-              dev_wwn = &xop->dst_tid_wwn[0];
+-      else
+-              dev_wwn = &xop->src_tid_wwn[0];
+-
+       mutex_lock(&g_device_mutex);
+       list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
+@@ -77,15 +72,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
+               if (rc != 0)
+                       continue;
+-              if (src) {
+-                      xop->dst_dev = se_dev;
+-                      pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
+-                              " se_dev\n", xop->dst_dev);
+-              } else {
+-                      xop->src_dev = se_dev;
+-                      pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located"
+-                              " se_dev\n", xop->src_dev);
+-              }
++              *found_dev = se_dev;
++              pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
+               rc = target_depend_item(&se_dev->dev_group.cg_item);
+               if (rc != 0) {
+@@ -242,9 +230,11 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
+       }
+       if (xop->op_origin == XCOL_SOURCE_RECV_OP)
+-              rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
++              rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
++                                              &xop->dst_dev);
+       else
+-              rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
++              rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
++                                              &xop->src_dev);
+       /*
+        * If a matching IEEE NAA 0x83 descriptor for the requested device
+        * is not located on this node, return COPY_ABORTED with ASQ/ASQC
+-- 
+2.27.0
+
diff --git a/queue-4.9/target-use-xcopy-segment-descriptor-cscd-ids.patch b/queue-4.9/target-use-xcopy-segment-descriptor-cscd-ids.patch
new file mode 100644 (file)
index 0000000..5b3517c
--- /dev/null
@@ -0,0 +1,221 @@
+From 0d108279abff653ce576e8de6695722013a33e27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 2 Jan 2017 18:04:07 +0100
+Subject: target: use XCOPY segment descriptor CSCD IDs
+
+From: David Disseldorp <ddiss@suse.de>
+
+[ Upstream commit 66640d35c1e4ef3c96ba5edb3c5e2ff8ab812e7a ]
+
+The XCOPY specification in SPC4r37 states that the XCOPY source and
+destination device(s) should be derived from the copy source and copy
+destination (CSCD) descriptor IDs in the XCOPY segment descriptor.
+
+The CSCD IDs are generally (for block -> block copies), indexes into
+the corresponding CSCD descriptor list, e.g.
+=================================
+EXTENDED COPY Header
+=================================
+CSCD Descriptor List
+- entry 0
+  + LU ID <--------------<------------------\
+- entry 1                                   |
+  + LU ID <______________<_____________     |
+=================================      |    |
+Segment Descriptor List                |    |
+- segment 0                            |    |
+  + src CSCD ID = 0 --------->---------+----/
+  + dest CSCD ID = 1 ___________>______|
+  + len
+  + src lba
+  + dest lba
+=================================
+
+Currently LIO completely ignores the src and dest CSCD IDs in the
+Segment Descriptor List, and instead assumes that the first entry in the
+CSCD list corresponds to the source, and the second to the destination.
+
+This commit removes this assumption, by ensuring that the Segment
+Descriptor List is parsed prior to processing the CSCD Descriptor List.
+CSCD Descriptor List processing is modified to compare the current list
+index with the previously obtained src and dest CSCD IDs.
+
+Additionally, XCOPY requests where the src and dest CSCD IDs refer to
+the CSCD Descriptor List entry can now be successfully processed.
+
+Fixes: cbf031f ("target: Add support for EXTENDED_COPY copy offload")
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=191381
+Signed-off-by: David Disseldorp <ddiss@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/target_core_xcopy.c | 79 ++++++++++++++++++------------
+ 1 file changed, 48 insertions(+), 31 deletions(-)
+
+diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
+index c4bd86976e450..b380f5e2af47d 100644
+--- a/drivers/target/target_core_xcopy.c
++++ b/drivers/target/target_core_xcopy.c
+@@ -97,7 +97,7 @@ static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
+ }
+ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
+-                              unsigned char *p, bool src)
++                              unsigned char *p, unsigned short cscd_index)
+ {
+       unsigned char *desc = p;
+       unsigned short ript;
+@@ -142,7 +142,13 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
+               return -EINVAL;
+       }
+-      if (src) {
++      if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
++              pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
++                       "dest\n", cscd_index);
++              return 0;
++      }
++
++      if (cscd_index == xop->stdi) {
+               memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
+               /*
+                * Determine if the source designator matches the local device
+@@ -154,10 +160,15 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
+                       pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
+                                       " received xop\n", xop->src_dev);
+               }
+-      } else {
++      }
++
++      if (cscd_index == xop->dtdi) {
+               memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
+               /*
+-               * Determine if the destination designator matches the local device
++               * Determine if the destination designator matches the local
++               * device. If @cscd_index corresponds to both source (stdi) and
++               * destination (dtdi), or dtdi comes after stdi, then
++               * XCOL_DEST_RECV_OP wins.
+                */
+               if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
+                               XCOPY_NAA_IEEE_REGEX_LEN)) {
+@@ -177,9 +188,9 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
+ {
+       struct se_device *local_dev = se_cmd->se_dev;
+       unsigned char *desc = p;
+-      int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0;
++      int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
++      unsigned short cscd_index = 0;
+       unsigned short start = 0;
+-      bool src = true;
+       *sense_ret = TCM_INVALID_PARAMETER_LIST;
+@@ -202,25 +213,19 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
+       while (start < tdll) {
+               /*
+-               * Check target descriptor identification with 0xE4 type with
+-               * use VPD 0x83 WWPN matching ..
++               * Check target descriptor identification with 0xE4 type, and
++               * compare the current index with the CSCD descriptor IDs in
++               * the segment descriptor. Use VPD 0x83 WWPN matching ..
+                */
+               switch (desc[0]) {
+               case 0xe4:
+                       rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
+-                                                      &desc[0], src);
++                                                      &desc[0], cscd_index);
+                       if (rc != 0)
+                               goto out;
+-                      /*
+-                       * Assume target descriptors are in source -> destination order..
+-                       */
+-                      if (src)
+-                              src = false;
+-                      else
+-                              src = true;
+                       start += XCOPY_TARGET_DESC_LEN;
+                       desc += XCOPY_TARGET_DESC_LEN;
+-                      ret++;
++                      cscd_index++;
+                       break;
+               default:
+                       pr_err("XCOPY unsupported descriptor type code:"
+@@ -229,12 +234,21 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
+               }
+       }
+-      if (xop->op_origin == XCOL_SOURCE_RECV_OP)
++      switch (xop->op_origin) {
++      case XCOL_SOURCE_RECV_OP:
+               rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
+                                               &xop->dst_dev);
+-      else
++              break;
++      case XCOL_DEST_RECV_OP:
+               rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
+                                               &xop->src_dev);
++              break;
++      default:
++              pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
++                      "stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
++              rc = -EINVAL;
++              break;
++      }
+       /*
+        * If a matching IEEE NAA 0x83 descriptor for the requested device
+        * is not located on this node, return COPY_ABORTED with ASQ/ASQC
+@@ -251,7 +265,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
+       pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
+                xop->dst_dev, &xop->dst_tid_wwn[0]);
+-      return ret;
++      return cscd_index;
+ out:
+       return -EINVAL;
+@@ -892,6 +906,20 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+               " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
+               tdll, sdll, inline_dl);
++      /*
++       * skip over the target descriptors until segment descriptors
++       * have been passed - CSCD ids are needed to determine src and dest.
++       */
++      seg_desc = &p[16] + tdll;
++
++      rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
++                                                  sdll, &ret);
++      if (rc <= 0)
++              goto out;
++
++      pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
++                              rc * XCOPY_SEGMENT_DESC_LEN);
++
+       rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
+       if (rc <= 0)
+               goto out;
+@@ -909,19 +937,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+       pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
+                               rc * XCOPY_TARGET_DESC_LEN);
+-      seg_desc = &p[16];
+-      seg_desc += (rc * XCOPY_TARGET_DESC_LEN);
+-
+-      rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
+-                                                  sdll, &ret);
+-      if (rc <= 0) {
+-              xcopy_pt_undepend_remotedev(xop);
+-              goto out;
+-      }
+       transport_kunmap_data_sg(se_cmd);
+-      pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
+-                              rc * XCOPY_SEGMENT_DESC_LEN);
+       INIT_WORK(&xop->xop_work, target_xcopy_do_work);
+       queue_work(xcopy_wq, &xop->xop_work);
+       return TCM_NO_SENSE;
+-- 
+2.27.0
+
diff --git a/queue-4.9/xcopy-loop-over-devices-using-idr-helper.patch b/queue-4.9/xcopy-loop-over-devices-using-idr-helper.patch
new file mode 100644 (file)
index 0000000..e996d75
--- /dev/null
@@ -0,0 +1,118 @@
+From 1cc45281b892f7d863643e63f08a52b1dee27a80 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Jun 2017 01:18:17 -0500
+Subject: xcopy: loop over devices using idr helper
+
+From: Mike Christie <mchristi@redhat.com>
+
+[ Upstream commit 6906d008b4b06e42cad393ac25bec76fbf31fabd ]
+
+This converts the xcopy code to use the idr helper. The next patch
+will drop the g_device_list and make g_device_mutex local to the
+target_core_device.c file.
+
+Signed-off-by: Mike Christie <mchristi@redhat.com>
+Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/target_core_xcopy.c | 70 +++++++++++++++++-------------
+ 1 file changed, 41 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
+index b380f5e2af47d..065669f9ca8cc 100644
+--- a/drivers/target/target_core_xcopy.c
++++ b/drivers/target/target_core_xcopy.c
+@@ -52,48 +52,60 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
+       return 0;
+ }
+-static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
+-                                      struct se_device **found_dev)
++struct xcopy_dev_search_info {
++      const unsigned char *dev_wwn;
++      struct se_device *found_dev;
++};
++
++static int target_xcopy_locate_se_dev_e4_iter(struct se_device *se_dev,
++                                            void *data)
+ {
+-      struct se_device *se_dev;
++      struct xcopy_dev_search_info *info = data;
+       unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+       int rc;
+-      mutex_lock(&g_device_mutex);
+-      list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
++      if (!se_dev->dev_attrib.emulate_3pc)
++              return 0;
+-              if (!se_dev->dev_attrib.emulate_3pc)
+-                      continue;
++      memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
++      target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
+-              memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
+-              target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
++      rc = memcmp(&tmp_dev_wwn[0], info->dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
++      if (rc != 0)
++              return 0;
+-              rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
+-              if (rc != 0)
+-                      continue;
++      info->found_dev = se_dev;
++      pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
+-              *found_dev = se_dev;
+-              pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
++      rc = target_depend_item(&se_dev->dev_group.cg_item);
++      if (rc != 0) {
++              pr_err("configfs_depend_item attempt failed: %d for se_dev: %p\n",
++                     rc, se_dev);
++              return rc;
++      }
+-              rc = target_depend_item(&se_dev->dev_group.cg_item);
+-              if (rc != 0) {
+-                      pr_err("configfs_depend_item attempt failed:"
+-                              " %d for se_dev: %p\n", rc, se_dev);
+-                      mutex_unlock(&g_device_mutex);
+-                      return rc;
+-              }
++      pr_debug("Called configfs_depend_item for se_dev: %p se_dev->se_dev_group: %p\n",
++               se_dev, &se_dev->dev_group);
++      return 1;
++}
++
++static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
++                                      struct se_device **found_dev)
++{
++      struct xcopy_dev_search_info info;
++      int ret;
+-              pr_debug("Called configfs_depend_item for se_dev: %p"
+-                      " se_dev->se_dev_group: %p\n", se_dev,
+-                      &se_dev->dev_group);
++      memset(&info, 0, sizeof(info));
++      info.dev_wwn = dev_wwn;
+-              mutex_unlock(&g_device_mutex);
++      ret = target_for_each_device(target_xcopy_locate_se_dev_e4_iter, &info);
++      if (ret == 1) {
++              *found_dev = info.found_dev;
+               return 0;
++      } else {
++              pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
++              return -EINVAL;
+       }
+-      mutex_unlock(&g_device_mutex);
+-
+-      pr_debug_ratelimited("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+-      return -EINVAL;
+ }
+ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
+-- 
+2.27.0
+