Blob Blame History Raw
From 71123ed19c51964db94ca2c04d8e3ff08209fe79 Mon Sep 17 00:00:00 2001
From: Mike Christie <michaelc@cs.wisc.edu>
Date: Wed, 29 Jul 2015 04:23:50 -0500
Subject: [PATCH] target: add COMPARE_AND_WRITE sg creation helper
References: fate#318836
Patch-mainline: Not yet, SES2 clustered LIO/RBD

bc core and the rbd backend driver want seperate scatterlists
for the write phase of COMPARE_AND_WRITE. This moves the sbc
code to a helper function.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Acked-by: David Disseldorp <ddiss@suse.de>
---
 drivers/target/target_core_sbc.c     |   74 +++++++++++++++++++++++------------
 include/target/target_core_backend.h |    1 
 2 files changed, 50 insertions(+), 25 deletions(-)

--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -449,13 +449,60 @@ static sense_reason_t compare_and_write_
 	return ret;
 }
 
+/**
+ * sbc_create_compare_and_write_sg - alloc and prep a sg for the write phase
+ * @cmd: se_cmd to copy scatterlist from.
+ *
+ * Takes the cmd's scatterlist and creates a new sg with only the write
+ * portion.
+*/
+struct scatterlist *sbc_create_compare_and_write_sg(struct se_cmd *cmd)
+{
+	struct se_device *dev = cmd->se_dev;
+	unsigned int block_size = dev->dev_attrib.block_size;
+	unsigned int len = cmd->t_task_nolb * block_size;
+	struct scatterlist *write_sg;
+	struct sg_mapping_iter m;
+	int i = 0;
+
+	write_sg = kmalloc_array(cmd->t_data_nents, sizeof(*write_sg),
+				 GFP_KERNEL);
+	if (!write_sg) {
+		pr_err("Unable to allocate compare_and_write sg\n");
+		return NULL;
+	}
+	sg_init_table(write_sg, cmd->t_data_nents);
+
+	sg_miter_start(&m, cmd->t_data_sg, cmd->t_data_nents, SG_MITER_TO_SG);
+	/*
+	 * Currently assumes NoLB=1 and SGLs are PAGE_SIZE..
+	 */
+	while (len) {
+		sg_miter_next(&m);
+
+		if (block_size < PAGE_SIZE) {
+			sg_set_page(&write_sg[i], m.page, block_size,
+				    m.piter.sg->offset + block_size);
+		} else {
+			sg_miter_next(&m);
+			sg_set_page(&write_sg[i], m.page, block_size,
+				    m.piter.sg->offset);
+		}
+		len -= block_size;
+		i++;
+	}
+	sg_miter_stop(&m);
+
+	return write_sg;
+}
+EXPORT_SYMBOL(sbc_create_compare_and_write_sg);
+
 static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success,
 						 int *post_ret)
 {
 	struct se_device *dev = cmd->se_dev;
 	struct scatterlist *write_sg = NULL, *sg;
 	unsigned char *buf = NULL, *addr;
-	struct sg_mapping_iter m;
 	unsigned int offset = 0, len;
 	unsigned int nlbas = cmd->t_task_nolb;
 	unsigned int block_size = dev->dev_attrib.block_size;
@@ -494,14 +541,12 @@ static sense_reason_t compare_and_write_
 		goto out;
 	}
 
-	write_sg = kmalloc_array(cmd->t_data_nents, sizeof(*write_sg),
-				 GFP_KERNEL);
+	write_sg = sbc_create_compare_and_write_sg(cmd);
 	if (!write_sg) {
 		pr_err("Unable to allocate compare_and_write sg\n");
 		ret = TCM_OUT_OF_RESOURCES;
 		goto out;
 	}
-	sg_init_table(write_sg, cmd->t_data_nents);
 	/*
 	 * Setup verify and write data payloads from total NumberLBAs.
 	 */
@@ -538,27 +583,6 @@ static sense_reason_t compare_and_write_
 			break;
 	}
 
-	i = 0;
-	len = cmd->t_task_nolb * block_size;
-	sg_miter_start(&m, cmd->t_data_sg, cmd->t_data_nents, SG_MITER_TO_SG);
-	/*
-	 * Currently assumes NoLB=1 and SGLs are PAGE_SIZE..
-	 */
-	while (len) {
-		sg_miter_next(&m);
-
-		if (block_size < PAGE_SIZE) {
-			sg_set_page(&write_sg[i], m.page, block_size,
-				    m.piter.sg->offset + block_size);
-		} else {
-			sg_miter_next(&m);
-			sg_set_page(&write_sg[i], m.page, block_size,
-				    m.piter.sg->offset);
-		}
-		len -= block_size;
-		i++;
-	}
-	sg_miter_stop(&m);
 	/*
 	 * Save the original SGL + nents values before updating to new
 	 * assignments, to be released in transport_free_pages() ->
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -73,6 +73,7 @@ void	target_complete_cmd_with_length(str
 
 void	transport_copy_sense_to_cmd(struct se_cmd *, unsigned char *);
 
+struct scatterlist *sbc_create_compare_and_write_sg(struct se_cmd *);
 sense_reason_t	spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
 sense_reason_t	spc_emulate_report_luns(struct se_cmd *cmd);
 sense_reason_t	spc_emulate_inquiry_std(struct se_cmd *, unsigned char *);