Blame SOURCES/kvm-iscsi-Implement-copy-offloading.patch

383d26
From e059872c2b30d6065411e7b11d6841efa69d57c4 Mon Sep 17 00:00:00 2001
383d26
From: Fam Zheng <famz@redhat.com>
383d26
Date: Fri, 29 Jun 2018 06:11:48 +0200
383d26
Subject: [PATCH 44/57] iscsi: Implement copy offloading
383d26
383d26
RH-Author: Fam Zheng <famz@redhat.com>
383d26
Message-id: <20180629061153.12687-9-famz@redhat.com>
383d26
Patchwork-id: 81159
383d26
O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v2 08/13] iscsi: Implement copy offloading
383d26
Bugzilla: 1482537
383d26
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
383d26
RH-Acked-by: Max Reitz <mreitz@redhat.com>
383d26
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
383d26
383d26
Issue EXTENDED COPY (LID1) command to implement the copy_range API.
383d26
383d26
The parameter data construction code is modified from libiscsi's
383d26
iscsi-dd.c.
383d26
383d26
Signed-off-by: Fam Zheng <famz@redhat.com>
383d26
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
383d26
Message-id: 20180601092648.24614-9-famz@redhat.com
383d26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
383d26
(cherry picked from commit 604dfaaa3270081da689991afe83d94d3e8231df)
383d26
Signed-off-by: Fam Zheng <famz@redhat.com>
383d26
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
383d26
---
383d26
 block/iscsi.c            | 219 +++++++++++++++++++++++++++++++++++++++++++++++
383d26
 include/scsi/constants.h |   4 +
383d26
 2 files changed, 223 insertions(+)
383d26
383d26
diff --git a/block/iscsi.c b/block/iscsi.c
383d26
index 338f3dd..fbcd5bb 100644
383d26
--- a/block/iscsi.c
383d26
+++ b/block/iscsi.c
383d26
@@ -2187,6 +2187,221 @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
383d26
     iscsi_allocmap_invalidate(iscsilun);
383d26
 }
383d26
 
383d26
+static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs,
383d26
+                                                 BdrvChild *src,
383d26
+                                                 uint64_t src_offset,
383d26
+                                                 BdrvChild *dst,
383d26
+                                                 uint64_t dst_offset,
383d26
+                                                 uint64_t bytes,
383d26
+                                                 BdrvRequestFlags flags)
383d26
+{
383d26
+    return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags);
383d26
+}
383d26
+
383d26
+static struct scsi_task *iscsi_xcopy_task(int param_len)
383d26
+{
383d26
+    struct scsi_task *task;
383d26
+
383d26
+    task = g_new0(struct scsi_task, 1);
383d26
+
383d26
+    task->cdb[0]     = EXTENDED_COPY;
383d26
+    task->cdb[10]    = (param_len >> 24) & 0xFF;
383d26
+    task->cdb[11]    = (param_len >> 16) & 0xFF;
383d26
+    task->cdb[12]    = (param_len >> 8) & 0xFF;
383d26
+    task->cdb[13]    = param_len & 0xFF;
383d26
+    task->cdb_size   = 16;
383d26
+    task->xfer_dir   = SCSI_XFER_WRITE;
383d26
+    task->expxferlen = param_len;
383d26
+
383d26
+    return task;
383d26
+}
383d26
+
383d26
+static void iscsi_populate_target_desc(unsigned char *desc, IscsiLun *lun)
383d26
+{
383d26
+    struct scsi_inquiry_device_designator *dd = lun->dd;
383d26
+
383d26
+    memset(desc, 0, 32);
383d26
+    desc[0] = 0xE4; /* IDENT_DESCR_TGT_DESCR */
383d26
+    desc[4] = dd->code_set;
383d26
+    desc[5] = (dd->designator_type & 0xF)
383d26
+        | ((dd->association & 3) << 4);
383d26
+    desc[7] = dd->designator_length;
383d26
+    memcpy(desc + 8, dd->designator, dd->designator_length);
383d26
+
383d26
+    desc[28] = 0;
383d26
+    desc[29] = (lun->block_size >> 16) & 0xFF;
383d26
+    desc[30] = (lun->block_size >> 8) & 0xFF;
383d26
+    desc[31] = lun->block_size & 0xFF;
383d26
+}
383d26
+
383d26
+static void iscsi_xcopy_desc_hdr(uint8_t *hdr, int dc, int cat, int src_index,
383d26
+                                 int dst_index)
383d26
+{
383d26
+    hdr[0] = 0x02; /* BLK_TO_BLK_SEG_DESCR */
383d26
+    hdr[1] = ((dc << 1) | cat) & 0xFF;
383d26
+    hdr[2] = (XCOPY_BLK2BLK_SEG_DESC_SIZE >> 8) & 0xFF;
383d26
+    /* don't account for the first 4 bytes in descriptor header*/
383d26
+    hdr[3] = (XCOPY_BLK2BLK_SEG_DESC_SIZE - 4 /* SEG_DESC_SRC_INDEX_OFFSET */) & 0xFF;
383d26
+    hdr[4] = (src_index >> 8) & 0xFF;
383d26
+    hdr[5] = src_index & 0xFF;
383d26
+    hdr[6] = (dst_index >> 8) & 0xFF;
383d26
+    hdr[7] = dst_index & 0xFF;
383d26
+}
383d26
+
383d26
+static void iscsi_xcopy_populate_desc(uint8_t *desc, int dc, int cat,
383d26
+                                      int src_index, int dst_index, int num_blks,
383d26
+                                      uint64_t src_lba, uint64_t dst_lba)
383d26
+{
383d26
+    iscsi_xcopy_desc_hdr(desc, dc, cat, src_index, dst_index);
383d26
+
383d26
+    /* The caller should verify the request size */
383d26
+    assert(num_blks < 65536);
383d26
+    desc[10] = (num_blks >> 8) & 0xFF;
383d26
+    desc[11] = num_blks & 0xFF;
383d26
+    desc[12] = (src_lba >> 56) & 0xFF;
383d26
+    desc[13] = (src_lba >> 48) & 0xFF;
383d26
+    desc[14] = (src_lba >> 40) & 0xFF;
383d26
+    desc[15] = (src_lba >> 32) & 0xFF;
383d26
+    desc[16] = (src_lba >> 24) & 0xFF;
383d26
+    desc[17] = (src_lba >> 16) & 0xFF;
383d26
+    desc[18] = (src_lba >> 8) & 0xFF;
383d26
+    desc[19] = src_lba & 0xFF;
383d26
+    desc[20] = (dst_lba >> 56) & 0xFF;
383d26
+    desc[21] = (dst_lba >> 48) & 0xFF;
383d26
+    desc[22] = (dst_lba >> 40) & 0xFF;
383d26
+    desc[23] = (dst_lba >> 32) & 0xFF;
383d26
+    desc[24] = (dst_lba >> 24) & 0xFF;
383d26
+    desc[25] = (dst_lba >> 16) & 0xFF;
383d26
+    desc[26] = (dst_lba >> 8) & 0xFF;
383d26
+    desc[27] = dst_lba & 0xFF;
383d26
+}
383d26
+
383d26
+static void iscsi_xcopy_populate_header(unsigned char *buf, int list_id, int str,
383d26
+                                        int list_id_usage, int prio,
383d26
+                                        int tgt_desc_len,
383d26
+                                        int seg_desc_len, int inline_data_len)
383d26
+{
383d26
+    buf[0] = list_id;
383d26
+    buf[1] = ((str & 1) << 5) | ((list_id_usage & 3) << 3) | (prio & 7);
383d26
+    buf[2] = (tgt_desc_len >> 8) & 0xFF;
383d26
+    buf[3] = tgt_desc_len & 0xFF;
383d26
+    buf[8] = (seg_desc_len >> 24) & 0xFF;
383d26
+    buf[9] = (seg_desc_len >> 16) & 0xFF;
383d26
+    buf[10] = (seg_desc_len >> 8) & 0xFF;
383d26
+    buf[11] = seg_desc_len & 0xFF;
383d26
+    buf[12] = (inline_data_len >> 24) & 0xFF;
383d26
+    buf[13] = (inline_data_len >> 16) & 0xFF;
383d26
+    buf[14] = (inline_data_len >> 8) & 0xFF;
383d26
+    buf[15] = inline_data_len & 0xFF;
383d26
+}
383d26
+
383d26
+static void iscsi_xcopy_data(struct iscsi_data *data,
383d26
+                             IscsiLun *src, int64_t src_lba,
383d26
+                             IscsiLun *dst, int64_t dst_lba,
383d26
+                             uint16_t num_blocks)
383d26
+{
383d26
+    uint8_t *buf;
383d26
+    const int src_offset = XCOPY_DESC_OFFSET;
383d26
+    const int dst_offset = XCOPY_DESC_OFFSET + IDENT_DESCR_TGT_DESCR_SIZE;
383d26
+    const int seg_offset = dst_offset + IDENT_DESCR_TGT_DESCR_SIZE;
383d26
+
383d26
+    data->size = XCOPY_DESC_OFFSET +
383d26
+                 IDENT_DESCR_TGT_DESCR_SIZE * 2 +
383d26
+                 XCOPY_BLK2BLK_SEG_DESC_SIZE;
383d26
+    data->data = g_malloc0(data->size);
383d26
+    buf = data->data;
383d26
+
383d26
+    /* Initialise the parameter list header */
383d26
+    iscsi_xcopy_populate_header(buf, 1, 0, 2 /* LIST_ID_USAGE_DISCARD */,
383d26
+                                0, 2 * IDENT_DESCR_TGT_DESCR_SIZE,
383d26
+                                XCOPY_BLK2BLK_SEG_DESC_SIZE,
383d26
+                                0);
383d26
+
383d26
+    /* Initialise CSCD list with one src + one dst descriptor */
383d26
+    iscsi_populate_target_desc(&buf[src_offset], src);
383d26
+    iscsi_populate_target_desc(&buf[dst_offset], dst);
383d26
+
383d26
+    /* Initialise one segment descriptor */
383d26
+    iscsi_xcopy_populate_desc(&buf[seg_offset], 0, 0, 0, 1, num_blocks,
383d26
+                              src_lba, dst_lba);
383d26
+}
383d26
+
383d26
+static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs,
383d26
+                                               BdrvChild *src,
383d26
+                                               uint64_t src_offset,
383d26
+                                               BdrvChild *dst,
383d26
+                                               uint64_t dst_offset,
383d26
+                                               uint64_t bytes,
383d26
+                                               BdrvRequestFlags flags)
383d26
+{
383d26
+    IscsiLun *dst_lun = dst->bs->opaque;
383d26
+    IscsiLun *src_lun;
383d26
+    struct IscsiTask iscsi_task;
383d26
+    struct iscsi_data data;
383d26
+    int r = 0;
383d26
+    int block_size;
383d26
+
383d26
+    if (src->bs->drv->bdrv_co_copy_range_to != iscsi_co_copy_range_to) {
383d26
+        return -ENOTSUP;
383d26
+    }
383d26
+    src_lun = src->bs->opaque;
383d26
+
383d26
+    if (!src_lun->dd || !dst_lun->dd) {
383d26
+        return -ENOTSUP;
383d26
+    }
383d26
+    if (!is_byte_request_lun_aligned(dst_offset, bytes, dst_lun)) {
383d26
+        return -ENOTSUP;
383d26
+    }
383d26
+    if (!is_byte_request_lun_aligned(src_offset, bytes, src_lun)) {
383d26
+        return -ENOTSUP;
383d26
+    }
383d26
+    if (dst_lun->block_size != src_lun->block_size ||
383d26
+        !dst_lun->block_size) {
383d26
+        return -ENOTSUP;
383d26
+    }
383d26
+
383d26
+    block_size = dst_lun->block_size;
383d26
+    if (bytes / block_size > 65535) {
383d26
+        return -ENOTSUP;
383d26
+    }
383d26
+
383d26
+    iscsi_xcopy_data(&data,
383d26
+                     src_lun, src_offset / block_size,
383d26
+                     dst_lun, dst_offset / block_size,
383d26
+                     bytes / block_size);
383d26
+
383d26
+    iscsi_co_init_iscsitask(dst_lun, &iscsi_task);
383d26
+
383d26
+    qemu_mutex_lock(&dst_lun->mutex);
383d26
+    iscsi_task.task = iscsi_xcopy_task(data.size);
383d26
+retry:
383d26
+    if (iscsi_scsi_command_async(dst_lun->iscsi, dst_lun->lun,
383d26
+                                 iscsi_task.task, iscsi_co_generic_cb,
383d26
+                                 &data,
383d26
+                                 &iscsi_task) != 0) {
383d26
+        r = -EIO;
383d26
+        goto out_unlock;
383d26
+    }
383d26
+
383d26
+    iscsi_co_wait_for_task(&iscsi_task, dst_lun);
383d26
+
383d26
+    if (iscsi_task.do_retry) {
383d26
+        iscsi_task.complete = 0;
383d26
+        goto retry;
383d26
+    }
383d26
+
383d26
+    if (iscsi_task.status != SCSI_STATUS_GOOD) {
383d26
+        r = iscsi_task.err_code;
383d26
+        goto out_unlock;
383d26
+    }
383d26
+
383d26
+out_unlock:
383d26
+    g_free(iscsi_task.task);
383d26
+    qemu_mutex_unlock(&dst_lun->mutex);
383d26
+    g_free(iscsi_task.err_str);
383d26
+    return r;
383d26
+}
383d26
+
383d26
 static QemuOptsList iscsi_create_opts = {
383d26
     .name = "iscsi-create-opts",
383d26
     .head = QTAILQ_HEAD_INITIALIZER(iscsi_create_opts.head),
383d26
@@ -2221,6 +2436,8 @@ static BlockDriver bdrv_iscsi = {
383d26
 
383d26
     .bdrv_co_block_status  = iscsi_co_block_status,
383d26
     .bdrv_co_pdiscard      = iscsi_co_pdiscard,
383d26
+    .bdrv_co_copy_range_from = iscsi_co_copy_range_from,
383d26
+    .bdrv_co_copy_range_to  = iscsi_co_copy_range_to,
383d26
     .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
383d26
     .bdrv_co_readv         = iscsi_co_readv,
383d26
     .bdrv_co_writev_flags  = iscsi_co_writev_flags,
383d26
@@ -2256,6 +2473,8 @@ static BlockDriver bdrv_iser = {
383d26
 
383d26
     .bdrv_co_block_status  = iscsi_co_block_status,
383d26
     .bdrv_co_pdiscard      = iscsi_co_pdiscard,
383d26
+    .bdrv_co_copy_range_from = iscsi_co_copy_range_from,
383d26
+    .bdrv_co_copy_range_to  = iscsi_co_copy_range_to,
383d26
     .bdrv_co_pwrite_zeroes = iscsi_co_pwrite_zeroes,
383d26
     .bdrv_co_readv         = iscsi_co_readv,
383d26
     .bdrv_co_writev_flags  = iscsi_co_writev_flags,
383d26
diff --git a/include/scsi/constants.h b/include/scsi/constants.h
383d26
index a141dd7..083a8e8 100644
383d26
--- a/include/scsi/constants.h
383d26
+++ b/include/scsi/constants.h
383d26
@@ -311,4 +311,8 @@
383d26
 #define MMC_PROFILE_HDDVD_RW_DL         0x005A
383d26
 #define MMC_PROFILE_INVALID             0xFFFF
383d26
 
383d26
+#define XCOPY_DESC_OFFSET 16
383d26
+#define IDENT_DESCR_TGT_DESCR_SIZE 32
383d26
+#define XCOPY_BLK2BLK_SEG_DESC_SIZE 28
383d26
+
383d26
 #endif
383d26
-- 
383d26
1.8.3.1
383d26