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 *);