From nobody Wed Dec 17 21:57:33 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.zoho.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; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498235410684797.0470790304141; Fri, 23 Jun 2017 09:30:10 -0700 (PDT) Received: from localhost ([::1]:36255 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dORTD-0008UP-44 for importer@patchew.org; Fri, 23 Jun 2017 12:30:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59551) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dORLt-00018f-T3 for qemu-devel@nongnu.org; Fri, 23 Jun 2017 12:22:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dORLs-0007eg-KP for qemu-devel@nongnu.org; Fri, 23 Jun 2017 12:22:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:19702) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dORLp-0007cX-NB; Fri, 23 Jun 2017 12:22:29 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B76AEA4FBE; Fri, 23 Jun 2017 16:22:28 +0000 (UTC) Received: from noname.redhat.com (ovpn-117-196.ams2.redhat.com [10.36.117.196]) by smtp.corp.redhat.com (Postfix) with ESMTP id C6F956EC75; Fri, 23 Jun 2017 16:22:27 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com B76AEA4FBE Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=kwolf@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com B76AEA4FBE From: Kevin Wolf To: qemu-block@nongnu.org Date: Fri, 23 Jun 2017 18:21:18 +0200 Message-Id: <1498234919-27316-21-git-send-email-kwolf@redhat.com> In-Reply-To: <1498234919-27316-1-git-send-email-kwolf@redhat.com> References: <1498234919-27316-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Fri, 23 Jun 2017 16:22:28 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 20/61] qcow2: Split do_perform_cow() into _read(), _encrypt() and _write() 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: kwolf@redhat.com, qemu-devel@nongnu.org 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: Alberto Garcia This patch splits do_perform_cow() into three separate functions to read, encrypt and write the COW regions. perform_cow() can now read both regions first, then encrypt them and finally write them to disk. The memory allocation is also done in this function now, using one single buffer large enough to hold both regions. Signed-off-by: Alberto Garcia Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 117 +++++++++++++++++++++++++++++++++++++---------= ---- 1 file changed, 87 insertions(+), 30 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4c03639..3c9ace8 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -403,34 +403,26 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t = sector_num, return 0; } =20 -static int coroutine_fn do_perform_cow(BlockDriverState *bs, - uint64_t src_cluster_offset, - uint64_t cluster_offset, - unsigned offset_in_cluster, - unsigned bytes) +static int coroutine_fn do_perform_cow_read(BlockDriverState *bs, + uint64_t src_cluster_offset, + unsigned offset_in_cluster, + uint8_t *buffer, + unsigned bytes) { - BDRVQcow2State *s =3D bs->opaque; QEMUIOVector qiov; - struct iovec iov; + struct iovec iov =3D { .iov_base =3D buffer, .iov_len =3D bytes }; int ret; =20 if (bytes =3D=3D 0) { return 0; } =20 - iov.iov_len =3D bytes; - iov.iov_base =3D qemu_try_blockalign(bs, iov.iov_len); - if (iov.iov_base =3D=3D NULL) { - return -ENOMEM; - } - qemu_iovec_init_external(&qiov, &iov, 1); =20 BLKDBG_EVENT(bs->file, BLKDBG_COW_READ); =20 if (!bs->drv) { - ret =3D -ENOMEDIUM; - goto out; + return -ENOMEDIUM; } =20 /* Call .bdrv_co_readv() directly instead of using the public block-la= yer @@ -440,39 +432,63 @@ static int coroutine_fn do_perform_cow(BlockDriverSta= te *bs, ret =3D bs->drv->bdrv_co_preadv(bs, src_cluster_offset + offset_in_clu= ster, bytes, &qiov, 0); if (ret < 0) { - goto out; + return ret; } =20 - if (bs->encrypted) { + return 0; +} + +static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, + uint64_t src_cluster_offse= t, + unsigned offset_in_cluster, + uint8_t *buffer, + unsigned bytes) +{ + if (bytes && bs->encrypted) { + BDRVQcow2State *s =3D bs->opaque; int64_t sector =3D (src_cluster_offset + offset_in_cluster) >> BDRV_SECTOR_BITS; assert(s->cipher); assert((offset_in_cluster & ~BDRV_SECTOR_MASK) =3D=3D 0); assert((bytes & ~BDRV_SECTOR_MASK) =3D=3D 0); - if (qcow2_encrypt_sectors(s, sector, iov.iov_base, iov.iov_base, + if (qcow2_encrypt_sectors(s, sector, buffer, buffer, bytes >> BDRV_SECTOR_BITS, true, NULL) <= 0) { - ret =3D -EIO; - goto out; + return false; } } + return true; +} + +static int coroutine_fn do_perform_cow_write(BlockDriverState *bs, + uint64_t cluster_offset, + unsigned offset_in_cluster, + uint8_t *buffer, + unsigned bytes) +{ + QEMUIOVector qiov; + struct iovec iov =3D { .iov_base =3D buffer, .iov_len =3D bytes }; + int ret; + + if (bytes =3D=3D 0) { + return 0; + } + + qemu_iovec_init_external(&qiov, &iov, 1); =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, cluster_offset + offset_in_cluster, bytes); if (ret < 0) { - goto out; + return ret; } =20 BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); ret =3D bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster, bytes, &qiov, 0); if (ret < 0) { - goto out; + return ret; } =20 - ret =3D 0; -out: - qemu_vfree(iov.iov_base); - return ret; + return 0; } =20 =20 @@ -760,22 +776,62 @@ static int perform_cow(BlockDriverState *bs, QCowL2Me= ta *m) BDRVQcow2State *s =3D bs->opaque; Qcow2COWRegion *start =3D &m->cow_start; Qcow2COWRegion *end =3D &m->cow_end; + unsigned buffer_size; + uint8_t *start_buffer, *end_buffer; int ret; =20 + assert(start->nb_bytes <=3D UINT_MAX - end->nb_bytes); + if (start->nb_bytes =3D=3D 0 && end->nb_bytes =3D=3D 0) { return 0; } =20 + /* Reserve a buffer large enough to store the data from both the + * start and end COW regions. Add some padding in the middle if + * necessary to make sure that the end region is optimally aligned */ + buffer_size =3D QEMU_ALIGN_UP(start->nb_bytes, bdrv_opt_mem_align(bs))= + + end->nb_bytes; + start_buffer =3D qemu_try_blockalign(bs, buffer_size); + if (start_buffer =3D=3D NULL) { + return -ENOMEM; + } + /* The part of the buffer where the end region is located */ + end_buffer =3D start_buffer + buffer_size - end->nb_bytes; + qemu_co_mutex_unlock(&s->lock); - ret =3D do_perform_cow(bs, m->offset, m->alloc_offset, - start->offset, start->nb_bytes); + /* First we read the existing data from both COW regions */ + ret =3D do_perform_cow_read(bs, m->offset, start->offset, + start_buffer, start->nb_bytes); if (ret < 0) { goto fail; } =20 - ret =3D do_perform_cow(bs, m->offset, m->alloc_offset, - end->offset, end->nb_bytes); + ret =3D do_perform_cow_read(bs, m->offset, end->offset, + end_buffer, end->nb_bytes); + if (ret < 0) { + goto fail; + } + + /* Encrypt the data if necessary before writing it */ + if (bs->encrypted) { + if (!do_perform_cow_encrypt(bs, m->offset, start->offset, + start_buffer, start->nb_bytes) || + !do_perform_cow_encrypt(bs, m->offset, end->offset, + end_buffer, end->nb_bytes)) { + ret =3D -EIO; + goto fail; + } + } + + /* And now we can write everything */ + ret =3D do_perform_cow_write(bs, m->alloc_offset, start->offset, + start_buffer, start->nb_bytes); + if (ret < 0) { + goto fail; + } =20 + ret =3D do_perform_cow_write(bs, m->alloc_offset, end->offset, + end_buffer, end->nb_bytes); fail: qemu_co_mutex_lock(&s->lock); =20 @@ -788,6 +844,7 @@ fail: qcow2_cache_depends_on_flush(s->l2_table_cache); } =20 + qemu_vfree(start_buffer); return ret; } =20 --=20 1.8.3.1