From nobody Mon Apr 14 21:14:31 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1528111603664821.8012089052984; Mon, 4 Jun 2018 04:26:43 -0700 (PDT) Received: from localhost ([::1]:38955 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fPndK-0003mm-Jw for importer@patchew.org; Mon, 04 Jun 2018 07:26:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36771) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fPnY1-00086l-Dk for qemu-devel@nongnu.org; Mon, 04 Jun 2018 07:21:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fPnXz-0001YE-Uv for qemu-devel@nongnu.org; Mon, 04 Jun 2018 07:21:13 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:54208 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fPnXv-0001WP-Q3; Mon, 04 Jun 2018 07:21:07 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6A4517C6A9; Mon, 4 Jun 2018 11:21:07 +0000 (UTC) Received: from localhost (ovpn-116-202.ams2.redhat.com [10.36.116.202]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7EBFE112D172; Mon, 4 Jun 2018 11:21:01 +0000 (UTC) From: Stefan Hajnoczi To: Date: Mon, 4 Jun 2018 12:20:33 +0100 Message-Id: <20180604112036.2715-9-stefanha@redhat.com> In-Reply-To: <20180604112036.2715-1-stefanha@redhat.com> References: <20180604112036.2715-1-stefanha@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 04 Jun 2018 11:21:07 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 04 Jun 2018 11:21:07 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'stefanha@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 08/11] iscsi: Implement copy offloading X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Peter Maydell , Fam Zheng , Stefan Hajnoczi , qemu-block@nongnu.org, Peter Lieven , Max Reitz , Ronnie Sahlberg , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Fam Zheng Issue EXTENDED COPY (LID1) command to implement the copy_range API. The parameter data construction code is modified from libiscsi's iscsi-dd.c. Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Message-id: 20180601092648.24614-9-famz@redhat.com Signed-off-by: Stefan Hajnoczi --- include/scsi/constants.h | 4 + block/iscsi.c | 219 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) diff --git a/include/scsi/constants.h b/include/scsi/constants.h index a141dd71f8..083a8e887a 100644 --- a/include/scsi/constants.h +++ b/include/scsi/constants.h @@ -311,4 +311,8 @@ #define MMC_PROFILE_HDDVD_RW_DL 0x005A #define MMC_PROFILE_INVALID 0xFFFF =20 +#define XCOPY_DESC_OFFSET 16 +#define IDENT_DESCR_TGT_DESCR_SIZE 32 +#define XCOPY_BLK2BLK_SEG_DESC_SIZE 28 + #endif diff --git a/block/iscsi.c b/block/iscsi.c index 6a365cb07b..c2fbd8a8aa 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2205,6 +2205,221 @@ static void coroutine_fn iscsi_co_invalidate_cache(= BlockDriverState *bs, iscsi_allocmap_invalidate(iscsilun); } =20 +static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs, + BdrvChild *src, + uint64_t src_offset, + BdrvChild *dst, + uint64_t dst_offset, + uint64_t bytes, + BdrvRequestFlags flags) +{ + return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, = flags); +} + +static struct scsi_task *iscsi_xcopy_task(int param_len) +{ + struct scsi_task *task; + + task =3D g_new0(struct scsi_task, 1); + + task->cdb[0] =3D EXTENDED_COPY; + task->cdb[10] =3D (param_len >> 24) & 0xFF; + task->cdb[11] =3D (param_len >> 16) & 0xFF; + task->cdb[12] =3D (param_len >> 8) & 0xFF; + task->cdb[13] =3D param_len & 0xFF; + task->cdb_size =3D 16; + task->xfer_dir =3D SCSI_XFER_WRITE; + task->expxferlen =3D param_len; + + return task; +} + +static void iscsi_populate_target_desc(unsigned char *desc, IscsiLun *lun) +{ + struct scsi_inquiry_device_designator *dd =3D lun->dd; + + memset(desc, 0, 32); + desc[0] =3D 0xE4; /* IDENT_DESCR_TGT_DESCR */ + desc[4] =3D dd->code_set; + desc[5] =3D (dd->designator_type & 0xF) + | ((dd->association & 3) << 4); + desc[7] =3D dd->designator_length; + memcpy(desc + 8, dd->designator, dd->designator_length); + + desc[28] =3D 0; + desc[29] =3D (lun->block_size >> 16) & 0xFF; + desc[30] =3D (lun->block_size >> 8) & 0xFF; + desc[31] =3D lun->block_size & 0xFF; +} + +static void iscsi_xcopy_desc_hdr(uint8_t *hdr, int dc, int cat, int src_in= dex, + int dst_index) +{ + hdr[0] =3D 0x02; /* BLK_TO_BLK_SEG_DESCR */ + hdr[1] =3D ((dc << 1) | cat) & 0xFF; + hdr[2] =3D (XCOPY_BLK2BLK_SEG_DESC_SIZE >> 8) & 0xFF; + /* don't account for the first 4 bytes in descriptor header*/ + hdr[3] =3D (XCOPY_BLK2BLK_SEG_DESC_SIZE - 4 /* SEG_DESC_SRC_INDEX_OFFS= ET */) & 0xFF; + hdr[4] =3D (src_index >> 8) & 0xFF; + hdr[5] =3D src_index & 0xFF; + hdr[6] =3D (dst_index >> 8) & 0xFF; + hdr[7] =3D dst_index & 0xFF; +} + +static void iscsi_xcopy_populate_desc(uint8_t *desc, int dc, int cat, + int src_index, int dst_index, int nu= m_blks, + uint64_t src_lba, uint64_t dst_lba) +{ + iscsi_xcopy_desc_hdr(desc, dc, cat, src_index, dst_index); + + /* The caller should verify the request size */ + assert(num_blks < 65536); + desc[10] =3D (num_blks >> 8) & 0xFF; + desc[11] =3D num_blks & 0xFF; + desc[12] =3D (src_lba >> 56) & 0xFF; + desc[13] =3D (src_lba >> 48) & 0xFF; + desc[14] =3D (src_lba >> 40) & 0xFF; + desc[15] =3D (src_lba >> 32) & 0xFF; + desc[16] =3D (src_lba >> 24) & 0xFF; + desc[17] =3D (src_lba >> 16) & 0xFF; + desc[18] =3D (src_lba >> 8) & 0xFF; + desc[19] =3D src_lba & 0xFF; + desc[20] =3D (dst_lba >> 56) & 0xFF; + desc[21] =3D (dst_lba >> 48) & 0xFF; + desc[22] =3D (dst_lba >> 40) & 0xFF; + desc[23] =3D (dst_lba >> 32) & 0xFF; + desc[24] =3D (dst_lba >> 24) & 0xFF; + desc[25] =3D (dst_lba >> 16) & 0xFF; + desc[26] =3D (dst_lba >> 8) & 0xFF; + desc[27] =3D dst_lba & 0xFF; +} + +static void iscsi_xcopy_populate_header(unsigned char *buf, int list_id, i= nt str, + int list_id_usage, int prio, + int tgt_desc_len, + int seg_desc_len, int inline_data_= len) +{ + buf[0] =3D list_id; + buf[1] =3D ((str & 1) << 5) | ((list_id_usage & 3) << 3) | (prio & 7); + buf[2] =3D (tgt_desc_len >> 8) & 0xFF; + buf[3] =3D tgt_desc_len & 0xFF; + buf[8] =3D (seg_desc_len >> 24) & 0xFF; + buf[9] =3D (seg_desc_len >> 16) & 0xFF; + buf[10] =3D (seg_desc_len >> 8) & 0xFF; + buf[11] =3D seg_desc_len & 0xFF; + buf[12] =3D (inline_data_len >> 24) & 0xFF; + buf[13] =3D (inline_data_len >> 16) & 0xFF; + buf[14] =3D (inline_data_len >> 8) & 0xFF; + buf[15] =3D inline_data_len & 0xFF; +} + +static void iscsi_xcopy_data(struct iscsi_data *data, + IscsiLun *src, int64_t src_lba, + IscsiLun *dst, int64_t dst_lba, + uint16_t num_blocks) +{ + uint8_t *buf; + const int src_offset =3D XCOPY_DESC_OFFSET; + const int dst_offset =3D XCOPY_DESC_OFFSET + IDENT_DESCR_TGT_DESCR_SIZ= E; + const int seg_offset =3D dst_offset + IDENT_DESCR_TGT_DESCR_SIZE; + + data->size =3D XCOPY_DESC_OFFSET + + IDENT_DESCR_TGT_DESCR_SIZE * 2 + + XCOPY_BLK2BLK_SEG_DESC_SIZE; + data->data =3D g_malloc0(data->size); + buf =3D data->data; + + /* Initialise the parameter list header */ + iscsi_xcopy_populate_header(buf, 1, 0, 2 /* LIST_ID_USAGE_DISCARD */, + 0, 2 * IDENT_DESCR_TGT_DESCR_SIZE, + XCOPY_BLK2BLK_SEG_DESC_SIZE, + 0); + + /* Initialise CSCD list with one src + one dst descriptor */ + iscsi_populate_target_desc(&buf[src_offset], src); + iscsi_populate_target_desc(&buf[dst_offset], dst); + + /* Initialise one segment descriptor */ + iscsi_xcopy_populate_desc(&buf[seg_offset], 0, 0, 0, 1, num_blocks, + src_lba, dst_lba); +} + +static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs, + BdrvChild *src, + uint64_t src_offset, + BdrvChild *dst, + uint64_t dst_offset, + uint64_t bytes, + BdrvRequestFlags flags) +{ + IscsiLun *dst_lun =3D dst->bs->opaque; + IscsiLun *src_lun; + struct IscsiTask iscsi_task; + struct iscsi_data data; + int r =3D 0; + int block_size; + + if (src->bs->drv->bdrv_co_copy_range_to !=3D iscsi_co_copy_range_to) { + return -ENOTSUP; + } + src_lun =3D src->bs->opaque; + + if (!src_lun->dd || !dst_lun->dd) { + return -ENOTSUP; + } + if (!is_byte_request_lun_aligned(dst_offset, bytes, dst_lun)) { + return -ENOTSUP; + } + if (!is_byte_request_lun_aligned(src_offset, bytes, src_lun)) { + return -ENOTSUP; + } + if (dst_lun->block_size !=3D src_lun->block_size || + !dst_lun->block_size) { + return -ENOTSUP; + } + + block_size =3D dst_lun->block_size; + if (bytes / block_size > 65535) { + return -ENOTSUP; + } + + iscsi_xcopy_data(&data, + src_lun, src_offset / block_size, + dst_lun, dst_offset / block_size, + bytes / block_size); + + iscsi_co_init_iscsitask(dst_lun, &iscsi_task); + + qemu_mutex_lock(&dst_lun->mutex); + iscsi_task.task =3D iscsi_xcopy_task(data.size); +retry: + if (iscsi_scsi_command_async(dst_lun->iscsi, dst_lun->lun, + iscsi_task.task, iscsi_co_generic_cb, + &data, + &iscsi_task) !=3D 0) { + r =3D -EIO; + goto out_unlock; + } + + iscsi_co_wait_for_task(&iscsi_task, dst_lun); + + if (iscsi_task.do_retry) { + iscsi_task.complete =3D 0; + goto retry; + } + + if (iscsi_task.status !=3D SCSI_STATUS_GOOD) { + r =3D iscsi_task.err_code; + goto out_unlock; + } + +out_unlock: + g_free(iscsi_task.task); + qemu_mutex_unlock(&dst_lun->mutex); + g_free(iscsi_task.err_str); + return r; +} + static QemuOptsList iscsi_create_opts =3D { .name =3D "iscsi-create-opts", .head =3D QTAILQ_HEAD_INITIALIZER(iscsi_create_opts.head), @@ -2239,6 +2454,8 @@ static BlockDriver bdrv_iscsi =3D { =20 .bdrv_co_block_status =3D iscsi_co_block_status, .bdrv_co_pdiscard =3D iscsi_co_pdiscard, + .bdrv_co_copy_range_from =3D iscsi_co_copy_range_from, + .bdrv_co_copy_range_to =3D iscsi_co_copy_range_to, .bdrv_co_pwrite_zeroes =3D iscsi_co_pwrite_zeroes, .bdrv_co_readv =3D iscsi_co_readv, .bdrv_co_writev =3D iscsi_co_writev, @@ -2274,6 +2491,8 @@ static BlockDriver bdrv_iser =3D { =20 .bdrv_co_block_status =3D iscsi_co_block_status, .bdrv_co_pdiscard =3D iscsi_co_pdiscard, + .bdrv_co_copy_range_from =3D iscsi_co_copy_range_from, + .bdrv_co_copy_range_to =3D iscsi_co_copy_range_to, .bdrv_co_pwrite_zeroes =3D iscsi_co_pwrite_zeroes, .bdrv_co_readv =3D iscsi_co_readv, .bdrv_co_writev =3D iscsi_co_writev, --=20 2.17.1