From nobody Wed Nov 5 10:42:41 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 1534127730816455.6502612266469; Sun, 12 Aug 2018 19:35:30 -0700 (PDT) Received: from localhost ([::1]:37248 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fp2hd-0007mo-MA for importer@patchew.org; Sun, 12 Aug 2018 22:35:29 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53454) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fp2Ta-0003su-PT for qemu-devel@nongnu.org; Sun, 12 Aug 2018 22:21:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fp2TX-0008Qc-Uc for qemu-devel@nongnu.org; Sun, 12 Aug 2018 22:20:58 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:38952 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 1fp2TV-0008Mz-An; Sun, 12 Aug 2018 22:20:53 -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 E48174022414; Mon, 13 Aug 2018 02:20:52 +0000 (UTC) Received: from localhost (ovpn-204-21.brq.redhat.com [10.40.204.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C2E3D10073A7; Mon, 13 Aug 2018 02:20:50 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Mon, 13 Aug 2018 04:20:05 +0200 Message-Id: <20180813022006.7216-17-mreitz@redhat.com> In-Reply-To: <20180813022006.7216-1-mreitz@redhat.com> References: <20180813022006.7216-1-mreitz@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.6]); Mon, 13 Aug 2018 02:20:52 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 13 Aug 2018 02:20:52 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'mreitz@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH 16/17] mirror: Support COR with write-blocking 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 , Jeff Cody , Fam Zheng , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch adds a .bdrv_co_block_status() implementation for the mirror block job that reports an area as allocated iff source and target are in sync. This allows putting a copy-on-read node on top of a mirror node which automatically copies all data read from the source to the target. To make this perform better, bdrv_mirror_top_do_write() is modified to ignore BDRV_REQ_WRITE_UNCHANGED requests regarding the source, and only write them to the target (in write-blocking mode). Otherwise, using COR would result in all data read from the source that is not in sync with the target to be re-written to the source (which is not the intention of COR). Signed-off-by: Max Reitz --- block/mirror.c | 88 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index cba7de610e..625297fec1 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1304,29 +1304,40 @@ static int coroutine_fn bdrv_mirror_top_do_write(Bl= ockDriverState *bs, MirrorBDSOpaque *s =3D bs->opaque; int ret =3D 0; bool copy_to_target; + bool write_to_source; =20 copy_to_target =3D s->job->ret >=3D 0 && s->job->copy_mode =3D=3D MIRROR_COPY_MODE_WRITE_BLOCK= ING; =20 + /* WRITE_UNCHANGED requests are allocating writes, which in this + * case means that we should ensure the target is in sync with the + * source (by writing the data to the target). Therefore, if we + * do write to the target (only in write-blocking mode), skip + * writing the (unchanged) data to the source. */ + write_to_source =3D s->job->copy_mode !=3D MIRROR_COPY_MODE_WRITE_BLOC= KING || + !(flags & BDRV_REQ_WRITE_UNCHANGED); + if (copy_to_target) { op =3D active_write_prepare(s->job, offset, bytes); } =20 - switch (method) { - case MIRROR_METHOD_COPY: - ret =3D bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags); - break; + if (write_to_source) { + switch (method) { + case MIRROR_METHOD_COPY: + ret =3D bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flag= s); + break; =20 - case MIRROR_METHOD_ZERO: - ret =3D bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flags); - break; + case MIRROR_METHOD_ZERO: + ret =3D bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flag= s); + break; =20 - case MIRROR_METHOD_DISCARD: - ret =3D bdrv_co_pdiscard(bs->backing, offset, bytes); - break; + case MIRROR_METHOD_DISCARD: + ret =3D bdrv_co_pdiscard(bs->backing, offset, bytes); + break; =20 - default: - abort(); + default: + abort(); + } } =20 if (ret < 0) { @@ -1403,6 +1414,57 @@ static int coroutine_fn bdrv_mirror_top_pdiscard(Blo= ckDriverState *bs, NULL, 0); } =20 +/** + * Allocation status is determined by whether source and target are in + * sync: + * - If they are (dirty bitmap is clean), the data is considered to be + * allocated in this layer. Then, return BDRV_BLOCK_RAW so the + * request is forwarded to the source. + * - Dirty (unsynced) areas are considered unallocated. For those, + * return 0. + */ +static int coroutine_fn bdrv_mirror_top_block_status(BlockDriverState *bs, + bool want_zero, + int64_t offset, + int64_t bytes, + int64_t *pnum, + int64_t *map, + BlockDriverState **fi= le) +{ + MirrorBDSOpaque *s =3D bs->opaque; + BdrvDirtyBitmapIter *iter; + uint64_t dirty_offset, clean_offset; + int ret; + + *map =3D offset; + *file =3D bs->backing->bs; + + iter =3D bdrv_dirty_iter_new(s->job->dirty_bitmap); + bdrv_set_dirty_iter(iter, offset); + + bdrv_dirty_bitmap_lock(s->job->dirty_bitmap); + dirty_offset =3D bdrv_dirty_iter_next(iter); + bdrv_dirty_iter_free(iter); + if (dirty_offset > offset) { + /* Clean area */ + *pnum =3D MIN(dirty_offset - offset, bytes); + ret =3D BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID; + goto out; + } + + /* Dirty area, find next clean area */ + clean_offset =3D bdrv_dirty_bitmap_next_zero(s->job->dirty_bitmap, off= set); + bdrv_dirty_bitmap_unlock(s->job->dirty_bitmap); + + assert(clean_offset > offset); + *pnum =3D MIN(clean_offset - offset, bytes); + ret =3D 0; + +out: + bdrv_dirty_bitmap_unlock(s->job->dirty_bitmap); + return ret; +} + static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) { if (bs->backing =3D=3D NULL) { @@ -1442,7 +1504,7 @@ static BlockDriver bdrv_mirror_top =3D { .bdrv_co_pwrite_zeroes =3D bdrv_mirror_top_pwrite_zeroes, .bdrv_co_pdiscard =3D bdrv_mirror_top_pdiscard, .bdrv_co_flush =3D bdrv_mirror_top_flush, - .bdrv_co_block_status =3D bdrv_co_block_status_from_backing, + .bdrv_co_block_status =3D bdrv_mirror_top_block_status, .bdrv_refresh_filename =3D bdrv_mirror_top_refresh_filename, .bdrv_close =3D bdrv_mirror_top_close, .bdrv_child_perm =3D bdrv_mirror_top_child_perm, --=20 2.17.1