From nobody Tue Nov 18 22:46:02 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1613065178; cv=none; d=zohomail.com; s=zohoarc; b=Hijf6nD7hCzM2V+kgtV7lTJJnEdlMLG1J3xosYEv5/kuvHxJ/mrXQQsnKvyMOk3LhMgixBCxfq6dizZVVz9T9W0M7IhhkMFqiPKfe55MNeV3hBw8Y5W6uZjYxIKeIKaExHKBA70BWVP/2ZB8Esbt3XJGJLxessdgmYD6LyRAU+Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1613065178; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=ff2CjLDkPwbNKLJ5BQSgrJBV7Fz9U1wA0Z0fwv02+Fg=; b=dP4krFi9186MGrp3TAjnDNj6TLArCHpQNMrh0za7TCEDurNj9InMxLxoUjH1Zf31W9RnM1IpDtw3ee2bm9OXNjejmeBendj6ZNJn6vEjWtzboA5cTTgIL9y2EK5N2n4UweW/BRbzjvADjvEuUMM8NiLZvctEjULohSntZo4Wbgk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1613065178363508.3407123407475; Thu, 11 Feb 2021 09:39:38 -0800 (PST) Received: from localhost ([::1]:49106 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lAFwH-000065-7c for importer@patchew.org; Thu, 11 Feb 2021 12:39:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:55402) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lAFgL-0000Ls-D0 for qemu-devel@nongnu.org; Thu, 11 Feb 2021 12:23:09 -0500 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:44990) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1lAFg6-0006VI-HX for qemu-devel@nongnu.org; Thu, 11 Feb 2021 12:23:09 -0500 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-218-L655VliEMm2LabJ2IAVicw-1; Thu, 11 Feb 2021 12:22:47 -0500 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B43FE835E21; Thu, 11 Feb 2021 17:22:46 +0000 (UTC) Received: from localhost (ovpn-114-199.ams2.redhat.com [10.36.114.199]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 42CF11A8A3; Thu, 11 Feb 2021 17:22:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1613064169; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ff2CjLDkPwbNKLJ5BQSgrJBV7Fz9U1wA0Z0fwv02+Fg=; b=P+2FSOPhCMw5PvwO2NFeX0nisSC/3la6QNzSGAKjplHXXbWX9eknPeLhWve4rDBuQJs/pc KUUtIAgxWs2diN7Po1zKc/D8OfquM+KQsb6cbwPMpaEoJEIzJC4aLI7vxjqc0co6/EIAaX BHwVQuWlnulic9fzhm6IFfmTmpPSzDM= X-MC-Unique: L655VliEMm2LabJ2IAVicw-1 From: Max Reitz To: qemu-block@nongnu.org Subject: [PATCH 1/2] block/mirror: Fix mirror_top's permissions Date: Thu, 11 Feb 2021 18:22:41 +0100 Message-Id: <20210211172242.146671-2-mreitz@redhat.com> In-Reply-To: <20210211172242.146671-1-mreitz@redhat.com> References: <20210211172242.146671-1-mreitz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=mreitz@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=63.128.21.124; envelope-from=mreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.569, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Vladimir Sementsov-Ogievskiy , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" mirror_top currently shares all permissions, and takes only the WRITE permission (if some parent has taken that permission, too). That is wrong, though; mirror_top is a filter, so it should take permissions like any other filter does. For example, if the parent needs CONSISTENT_READ, we need to take that, too, and if it cannot share the WRITE permission, we cannot share it either. The exception is when mirror_top is used for active commit, where we cannot take CONSISTENT_READ (because it is deliberately unshared above the base node) and where we must share WRITE (so that it is shared for all images in the backing chain, so the mirror job can take it for the target BB). Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy --- block/mirror.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 8e1ad6eceb..1edfc3cc14 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -89,6 +89,7 @@ typedef struct MirrorBlockJob { typedef struct MirrorBDSOpaque { MirrorBlockJob *job; bool stop; + bool is_commit; } MirrorBDSOpaque; =20 struct MirrorOp { @@ -1513,13 +1514,27 @@ static void bdrv_mirror_top_child_perm(BlockDriverS= tate *bs, BdrvChild *c, return; } =20 - /* Must be able to forward guest writes to the real image */ - *nperm =3D 0; - if (perm & BLK_PERM_WRITE) { - *nperm |=3D BLK_PERM_WRITE; - } + bdrv_default_perms(bs, c, role, reopen_queue, + perm, shared, nperm, nshared); =20 - *nshared =3D BLK_PERM_ALL; + if (s->is_commit) { + /* + * For commit jobs, we cannot take CONSISTENT_READ, because + * that permission is unshared for everything above the base + * node (except for filters on the base node). + * We also have to force-share the WRITE permission, or + * otherwise we would block ourselves at the base node (if + * writes are blocked for a node, they are also blocked for + * its backing file). + * (We could also share RESIZE, because it may be needed for + * the target if its size is less than the top node's; but + * bdrv_default_perms_for_cow() automatically shares RESIZE + * for backing nodes if WRITE is shared, so there is no need + * to do it here.) + */ + *nperm &=3D ~BLK_PERM_CONSISTENT_READ; + *nshared |=3D BLK_PERM_WRITE; + } } =20 /* Dummy node that provides consistent read to its users without requiring= it @@ -1583,6 +1598,8 @@ static BlockJob *mirror_start_job( return NULL; } =20 + target_is_backing =3D bdrv_chain_contains(bs, target); + /* In the case of active commit, add dummy driver to provide consistent * reads on the top, while disabling it in the intermediate nodes, and= make * the backing chain writable. */ @@ -1605,6 +1622,8 @@ static BlockJob *mirror_start_job( bs_opaque =3D g_new0(MirrorBDSOpaque, 1); mirror_top_bs->opaque =3D bs_opaque; =20 + bs_opaque->is_commit =3D target_is_backing; + /* bdrv_append takes ownership of the mirror_top_bs reference, need to= keep * it alive until block_job_create() succeeds even if bs has no parent= . */ bdrv_ref(mirror_top_bs); @@ -1646,7 +1665,6 @@ static BlockJob *mirror_start_job( target_perms =3D BLK_PERM_WRITE; target_shared_perms =3D BLK_PERM_WRITE_UNCHANGED; =20 - target_is_backing =3D bdrv_chain_contains(bs, target); if (target_is_backing) { int64_t bs_size, target_size; bs_size =3D bdrv_getlength(bs); --=20 2.29.2 From nobody Tue Nov 18 22:46:02 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1613064998; cv=none; d=zohomail.com; s=zohoarc; b=hBQ63jXodviRDXEOioods7IWLey0fwInZX/Xr5MdKF4RBAFfEcgRkWiKEd1NAAYWD3KD3v9cDmD0+m5RT9gErV43xAcBTzXRbXjnJ6H6tidmGheZ8osL1W+M8M/h1V6oRH+5AXXAAwgHqO0BKMiDXx6DL0fdnf62u5/RNZ5As94= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1613064998; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=Fn/jK3u3iNYinDSLvddg0iGOwNNI5hFvrYnbjj3est0=; b=HGgsyWIqsT75HqxuTRgUa/arN9bOybnayk2QLkGoBJ+2ec04VTn9XT8MUQbYfCl++VAtKmxcC5you399cBVcDuq+yS5JLUtT8QWW/JkYcBa0bWLwM4IIK0MuOVcYyPPTa6I9JPi8KZ93mRFhUJAp1uyxBWCCtEjpQCzRvpERFWY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1613064998270951.3735812016996; Thu, 11 Feb 2021 09:36:38 -0800 (PST) Received: from localhost ([::1]:40386 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lAFtN-0004s9-45 for importer@patchew.org; Thu, 11 Feb 2021 12:36:37 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:55376) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lAFgB-00007p-Bq for qemu-devel@nongnu.org; Thu, 11 Feb 2021 12:22:59 -0500 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:34300) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1lAFg6-0006WE-IH for qemu-devel@nongnu.org; Thu, 11 Feb 2021 12:22:59 -0500 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-538-pYnT2M71NyWKeZE-9rcvCQ-1; Thu, 11 Feb 2021 12:22:50 -0500 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 mimecast-mx01.redhat.com (Postfix) with ESMTPS id 75410107ACF6; Thu, 11 Feb 2021 17:22:49 +0000 (UTC) Received: from localhost (ovpn-114-199.ams2.redhat.com [10.36.114.199]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D6FFF60C64; Thu, 11 Feb 2021 17:22:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1613064172; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Fn/jK3u3iNYinDSLvddg0iGOwNNI5hFvrYnbjj3est0=; b=YovJKVBSBWMuztlnfsU9rqsBNnYwxeR+CJ7Fa7HEUuGzhWtC2YSGISdI/GtWWRjPsuFr1N wv9m+4bGZdUJyEDy/zke97//fb/6Fc+Y2M4WJ9gB5ymcJO2iSD7RaPzMyU2DmJ/XIJ8lTq 2bBVTksSGNXVeqxbuebf+++44MQeE+o= X-MC-Unique: pYnT2M71NyWKeZE-9rcvCQ-1 From: Max Reitz To: qemu-block@nongnu.org Subject: [PATCH 2/2] file-posix: Cache next hole Date: Thu, 11 Feb 2021 18:22:42 +0100 Message-Id: <20210211172242.146671-3-mreitz@redhat.com> In-Reply-To: <20210211172242.146671-1-mreitz@redhat.com> References: <20210211172242.146671-1-mreitz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=mreitz@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=63.128.21.124; envelope-from=mreitz@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -33 X-Spam_score: -3.4 X-Spam_bar: --- X-Spam_report: (-3.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.569, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Vladimir Sementsov-Ogievskiy , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" We have repeatedly received reports that SEEK_HOLE and SEEK_DATA are slow on certain filesystems and/or under certain circumstances. That is why we generally try to avoid it (which is why bdrv_co_block_status() has the @want_zero parameter, and which is why qcow2 has a metadata preallocation detection, so we do not fall through to the protocol layer to discover which blocks are zero, unless that is really necessary (i.e., for metadata-preallocated images)). In addition to those measures, we can also try to speed up zero detection by letting file-posix cache some hole location information, namely where the next hole after the most recently queried offset is. This helps especially for images that are (nearly) fully allocated, which is coincidentally also the case where querying for zero information cannot gain us much. Note that this of course only works so long as we have no concurrent writers to the image, which is the case when the WRITE capability is not shared. Alternatively (or perhaps as an improvement in the future), we could let file-posix keep track of what it knows is zero and what it knows is non-zero with bitmaps, which would help images that actually have a significant number of holes (where this implementation here cannot do much). But for such images, SEEK_HOLE/DATA are generally faster (they do not need to seek through the whole file), and the performance lost by querying the block status does not feel as bad because it is outweighed by the performance that can be saved by special-cases zeroed areas, so focussing on images that are (nearly) fully allocated is more important. Signed-off-by: Max Reitz Reviewed-by: Eric Blake --- block/file-posix.c | 81 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index 05079b40ca..2ca0a2e05b 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -172,6 +172,11 @@ typedef struct BDRVRawState { } stats; =20 PRManager *pr_mgr; + + bool can_cache_next_zero_offset; + bool next_zero_offset_valid; + uint64_t next_zero_offset_from; + uint64_t next_zero_offset; } BDRVRawState; =20 typedef struct BDRVRawReopenState { @@ -2049,7 +2054,25 @@ static int coroutine_fn raw_co_pwritev(BlockDriverSt= ate *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags) { + BDRVRawState *s =3D bs->opaque; + assert(flags =3D=3D 0); + + /* + * If offset is just above s->next_zero_offset, the hole that was + * reportedly there might be removed from the file (because only + * whole filesystem clusters can be zeroed). But that does not + * matter, because block-status does not care about whether there + * actually is a hole, but just about whether there are zeroes + * there - and this write will not make those zeroes non-zero. + */ + if (s->next_zero_offset_valid && + offset <=3D s->next_zero_offset && + offset + bytes > s->next_zero_offset) + { + s->next_zero_offset_valid =3D false; + } + return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE); } =20 @@ -2183,6 +2206,10 @@ static int coroutine_fn raw_co_truncate(BlockDriverS= tate *bs, int64_t offset, struct stat st; int ret; =20 + if (s->next_zero_offset_valid && offset < s->next_zero_offset) { + s->next_zero_offset_valid =3D false; + } + if (fstat(s->fd, &st)) { ret =3D -errno; error_setg_errno(errp, -ret, "Failed to fstat() the file"); @@ -2616,8 +2643,17 @@ static int coroutine_fn raw_co_delete_file(BlockDriv= erState *bs, static int find_allocation(BlockDriverState *bs, off_t start, off_t *data, off_t *hole) { -#if defined SEEK_HOLE && defined SEEK_DATA BDRVRawState *s =3D bs->opaque; + + if (s->next_zero_offset_valid) { + if (start >=3D s->next_zero_offset_from && start < s->next_zero_of= fset) { + *data =3D start; + *hole =3D s->next_zero_offset; + return 0; + } + } + +#if defined SEEK_HOLE && defined SEEK_DATA off_t offs; =20 /* @@ -2716,6 +2752,7 @@ static int coroutine_fn raw_co_block_status(BlockDriv= erState *bs, int64_t *map, BlockDriverState **file) { + BDRVRawState *s =3D bs->opaque; off_t data =3D 0, hole =3D 0; int ret; =20 @@ -2734,6 +2771,7 @@ static int coroutine_fn raw_co_block_status(BlockDriv= erState *bs, } =20 ret =3D find_allocation(bs, offset, &data, &hole); + s->next_zero_offset_valid =3D false; if (ret =3D=3D -ENXIO) { /* Trailing hole */ *pnum =3D bytes; @@ -2761,6 +2799,12 @@ static int coroutine_fn raw_co_block_status(BlockDri= verState *bs, } =20 ret =3D BDRV_BLOCK_DATA; + + if (s->can_cache_next_zero_offset) { + s->next_zero_offset_valid =3D true; + s->next_zero_offset_from =3D offset; + s->next_zero_offset =3D hole; + } } else { /* On a hole, compute bytes to the beginning of the next extent. = */ assert(hole =3D=3D offset); @@ -2910,6 +2954,13 @@ raw_do_pdiscard(BlockDriverState *bs, int64_t offset= , int bytes, bool blkdev) RawPosixAIOData acb; int ret; =20 + if (s->next_zero_offset_valid && + offset <=3D s->next_zero_offset && + offset + bytes > s->next_zero_offset_from) + { + s->next_zero_offset_valid =3D false; + } + acb =3D (RawPosixAIOData) { .bs =3D bs, .aio_fildes =3D s->fd, @@ -2941,6 +2992,17 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t o= ffset, int bytes, RawPosixAIOData acb; ThreadPoolFunc *handler; =20 + if (s->next_zero_offset_valid && + offset < s->next_zero_offset && + offset + bytes > s->next_zero_offset_from) + { + if (offset > s->next_zero_offset_from) { + s->next_zero_offset =3D offset; + } else { + s->next_zero_offset_valid =3D false; + } + } + #ifdef CONFIG_FALLOCATE if (offset + bytes > bs->total_sectors * BDRV_SECTOR_SIZE) { BdrvTrackedRequest *req; @@ -3155,6 +3217,15 @@ static void raw_set_perm(BlockDriverState *bs, uint6= 4_t perm, uint64_t shared) raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL); s->perm =3D perm; s->shared_perm =3D shared; + + /* + * We can only cache anything if there are no external writers on + * the image. + */ + s->can_cache_next_zero_offset =3D !(shared & BLK_PERM_WRITE); + if (!s->can_cache_next_zero_offset) { + s->next_zero_offset_valid =3D false; + } } =20 static void raw_abort_perm_update(BlockDriverState *bs) @@ -3203,6 +3274,14 @@ static int coroutine_fn raw_co_copy_range_to(BlockDr= iverState *bs, return -EIO; } =20 + /* Same as in raw_co_pwritev() */ + if (s->next_zero_offset_valid && + dst_offset <=3D s->next_zero_offset && + dst_offset + bytes > s->next_zero_offset_from) + { + s->next_zero_offset_valid =3D false; + } + acb =3D (RawPosixAIOData) { .bs =3D bs, .aio_type =3D QEMU_AIO_COPY_RANGE, --=20 2.29.2