From nobody Wed May 8 12:57:40 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510346025726360.2343583816987; Fri, 10 Nov 2017 12:33:45 -0800 (PST) Received: from localhost ([::1]:43388 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDFzd-0002g3-Mu for importer@patchew.org; Fri, 10 Nov 2017 15:33:37 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54845) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDFxY-0001B4-Q5 for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:30 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eDFxX-00043K-O9 for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:28 -0500 Received: from mx1.redhat.com ([209.132.183.28]:37120) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eDFxS-0003vQ-F3; Fri, 10 Nov 2017 15:31:22 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 95C1E6A7D7; Fri, 10 Nov 2017 20:31:21 +0000 (UTC) Received: from localhost (ovpn-204-126.brq.redhat.com [10.40.204.126]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 72A106F922; Fri, 10 Nov 2017 20:31:18 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Fri, 10 Nov 2017 21:31:07 +0100 Message-Id: <20171110203111.7666-2-mreitz@redhat.com> In-Reply-To: <20171110203111.7666-1-mreitz@redhat.com> References: <20171110203111.7666-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Fri, 10 Nov 2017 20:31:21 +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] [PATCH for-2.11 1/5] qcow2: check_errors are fatal 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 , John Snow , Alberto Garcia , qemu-devel@nongnu.org, Max Reitz 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" When trying to repair a dirty image, qcow2_check() may apparently succeed (no really fatal error occurred that would prevent the check from continuing), but if check_errors in the result object is non-zero, we cannot trust the image to be usable. Reported-by: R. Nageswara Sastry Buglink: https://bugs.launchpad.net/qemu/+bug/1728639 Signed-off-by: Max Reitz Reviewed-by: Eric Blake --- block/qcow2.c | 5 ++++- tests/qemu-iotests/060 | 20 ++++++++++++++++++++ tests/qemu-iotests/060.out | 23 +++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/block/qcow2.c b/block/qcow2.c index 92e5d548e3..d4fcb0250d 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1475,7 +1475,10 @@ static int qcow2_do_open(BlockDriverState *bs, QDict= *options, int flags, BdrvCheckResult result =3D {0}; =20 ret =3D qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS); - if (ret < 0) { + if (ret < 0 || result.check_errors) { + if (ret >=3D 0) { + ret =3D -EIO; + } error_setg_errno(errp, -ret, "Could not repair dirty image"); goto fail; } diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index fae08b03bf..56bdf1ee2e 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -301,6 +301,26 @@ _make_test_img 64M poke_file "$TEST_IMG" "48" "\x00\x00\x00\x00\x00\x00\x00\x0= 0" $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io =20 +echo +echo "=3D=3D=3D Testing dirty corrupt image =3D=3D=3D" +echo + +_make_test_img 64M + +# Let the refblock appear unaligned +poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\xff\xff\x2a\x0= 0" +# Mark the image dirty, thus forcing an automatic check when opening it +poke_file "$TEST_IMG" 72 "\x00\x00\x00\x00\x00\x00\x00\x01" +# Open the image (qemu should refuse to do so) +$QEMU_IO -c close "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt + +echo '--- Repairing ---' + +# The actual repair should have happened (because of the dirty bit), +# but some cleanup may have failed (like freeing the old reftable) +# because the image was already marked corrupt by that point +_check_test_img -r all + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 62c22701b8..f013fe73c0 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -284,4 +284,27 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table= at offset 0; further corruption events will be suppressed write failed: Input/output error + +=3D=3D=3D Testing dirty corrupt image =3D=3D=3D + +Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 +ERROR refcount block 0 is not cluster aligned; refcount table entry corrup= ted +IMGFMT: Marking image as corrupt: Refblock offset 0xffff2a00 unaligned (re= ftable index: 0); further corruption events will be suppressed +Can't get refcount for cluster 0: Input/output error +Can't get refcount for cluster 1: Input/output error +Can't get refcount for cluster 2: Input/output error +Can't get refcount for cluster 3: Input/output error +Rebuilding refcount structure +Repairing cluster 1 refcount=3D1 reference=3D0 +can't open device TEST_DIR/t.IMGFMT: Could not repair dirty image: Input/o= utput error +--- Repairing --- +Leaked cluster 1 refcount=3D1 reference=3D0 +Repairing cluster 1 refcount=3D1 reference=3D0 +The following inconsistencies were found and repaired: + + 1 leaked clusters + 0 corruptions + +Double checking the fixed image now... +No errors were found on the image. *** done --=20 2.13.6 From nobody Wed May 8 12:57:40 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510346164819922.6230041845931; Fri, 10 Nov 2017 12:36:04 -0800 (PST) Received: from localhost ([::1]:43403 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDG1z-0004n0-WF for importer@patchew.org; Fri, 10 Nov 2017 15:36:04 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54865) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDFxb-0001E9-Qj for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:35 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eDFxa-00045O-PJ for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:31 -0500 Received: from mx1.redhat.com ([209.132.183.28]:35772) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eDFxY-00042r-2E; Fri, 10 Nov 2017 15:31:28 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 337995D9EB; Fri, 10 Nov 2017 20:31:27 +0000 (UTC) Received: from localhost (ovpn-204-126.brq.redhat.com [10.40.204.126]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 99B914DA68; Fri, 10 Nov 2017 20:31:23 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Fri, 10 Nov 2017 21:31:08 +0100 Message-Id: <20171110203111.7666-3-mreitz@redhat.com> In-Reply-To: <20171110203111.7666-1-mreitz@redhat.com> References: <20171110203111.7666-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Fri, 10 Nov 2017 20:31:27 +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] [PATCH for-2.11 2/5] qcow2: Unaligned zero cluster in handle_alloc() 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 , John Snow , Alberto Garcia , qemu-devel@nongnu.org, Max Reitz 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" We should check whether the cluster offset we are about to use is actually valid; that is, whether it is aligned to cluster boundaries. Reported-by: R. Nageswara Sastry Buglink: https://bugs.launchpad.net/qemu/+bug/1728643 Buglink: https://bugs.launchpad.net/qemu/+bug/1728657 Signed-off-by: Max Reitz Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake --- block/qcow2-cluster.c | 13 ++++++++++++- tests/qemu-iotests/060 | 16 ++++++++++++++++ tests/qemu-iotests/060.out | 10 ++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 2e072ed155..a3fec27bf9 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1308,10 +1308,21 @@ static int handle_alloc(BlockDriverState *bs, uint6= 4_t guest_offset, (!*host_offset || start_of_cluster(s, *host_offset) =3D=3D (entry & L2E_OFFSET_MASK= ))) { + int preallocated_nb_clusters; + + if (offset_into_cluster(s, entry & L2E_OFFSET_MASK)) { + qcow2_signal_corruption(bs, true, -1, -1, "Preallocated zero " + "cluster offset %#llx unaligned (guest= " + "offset: %#" PRIx64 ")", + entry & L2E_OFFSET_MASK, guest_offset); + ret =3D -EIO; + goto fail; + } + /* Try to reuse preallocated zero clusters; contiguous normal clus= ters * would be fine, too, but count_cow_clusters() above has limited * nb_clusters already to a range of COW clusters */ - int preallocated_nb_clusters =3D + preallocated_nb_clusters =3D count_contiguous_clusters(nb_clusters, s->cluster_size, &l2_table[l2_index], QCOW_OFLAG_COPI= ED); assert(preallocated_nb_clusters > 0); diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 56bdf1ee2e..49bc89df38 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -321,6 +321,22 @@ echo '--- Repairing ---' # because the image was already marked corrupt by that point _check_test_img -r all =20 +echo +echo "=3D=3D=3D Writing to an unaligned preallocated zero cluster =3D=3D= =3D" +echo + +_make_test_img 64M + +# Allocate the L2 table +$QEMU_IO -c "write 0 64k" -c "discard 0 64k" "$TEST_IMG" | _filter_qemu_io +# Pretend there is a preallocated zero cluster somewhere inside the +# image header +poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x00\x2a\x01" +# Let's write to it! +$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io + +# Can't repair this yet (TODO: We can just deallocate the cluster) + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index f013fe73c0..c583076808 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -307,4 +307,14 @@ The following inconsistencies were found and repaired: =20 Double checking the fixed image now... No errors were found on the image. + +=3D=3D=3D Writing to an unaligned preallocated zero cluster =3D=3D=3D + +Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 u= naligned (guest offset: 0); further corruption events will be suppressed +write failed: Input/output error *** done --=20 2.13.6 From nobody Wed May 8 12:57:40 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) 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=temperror (zoho.com: Error in retrieving data from DNS) 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 1510346313234588.8848528472308; Fri, 10 Nov 2017 12:38:33 -0800 (PST) Received: from localhost ([::1]:43412 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDG4I-0006bT-NZ for importer@patchew.org; Fri, 10 Nov 2017 15:38:26 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54916) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDFxj-0001L3-7j for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:41 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eDFxh-0004FD-Em for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:39 -0500 Received: from mx1.redhat.com ([209.132.183.28]:49860) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eDFxd-00046r-3c; Fri, 10 Nov 2017 15:31:33 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 453B361475; Fri, 10 Nov 2017 20:31:32 +0000 (UTC) Received: from localhost (ovpn-204-126.brq.redhat.com [10.40.204.126]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 349BB62697; Fri, 10 Nov 2017 20:31:29 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Fri, 10 Nov 2017 21:31:09 +0100 Message-Id: <20171110203111.7666-4-mreitz@redhat.com> In-Reply-To: <20171110203111.7666-1-mreitz@redhat.com> References: <20171110203111.7666-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Fri, 10 Nov 2017 20:31:32 +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] [PATCH for-2.11 3/5] block: Guard against NULL bs->drv 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 , John Snow , Alberto Garcia , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_6 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" We currently do not guard everywhere against a NULL bs->drv where we should be doing so. Most of the places fixed here just do not care about that case at all. Some care implicitly, e.g. through a prior function call to bdrv_getlength() which would always fail for an ejected BDS. Add an assert there to make it more obvious. Other places seem to care, but do so insufficiently: Freeing clusters in a qcow2 image is an error-free operation, but it may leave the image in an unusable state anyway. Giving qcow2_free_clusters() an error code is not really viable, it is much easier to note that bs->drv may be NULL even after a successful driver call. This concerns bdrv_co_flush(), and the way the check is added to bdrv_co_pdiscard() (in every iteration instead of only once). Finally, some places employ at least an assert(bs->drv); somewhere, that may be reasonable (such as in the reopen code), but in bdrv_has_zero_init(), it is definitely not. Returning 0 there in case of an ejected BDS saves us much headache instead. Reported-by: R. Nageswara Sastry Buglink: https://bugs.launchpad.net/qemu/+bug/1728660 Signed-off-by: Max Reitz Reviewed-by: Eric Blake --- block.c | 19 ++++++++++++++++++- block/io.c | 36 ++++++++++++++++++++++++++++++++++++ block/qapi.c | 8 +++++++- block/replication.c | 15 +++++++++++++++ block/vvfat.c | 2 +- tests/qemu-iotests/060 | 22 ++++++++++++++++++++++ tests/qemu-iotests/060.out | 31 +++++++++++++++++++++++++++++++ 7 files changed, 130 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index cec4e9a8d6..dce20ed5e7 100644 --- a/block.c +++ b/block.c @@ -720,6 +720,10 @@ static int refresh_total_sectors(BlockDriverState *bs,= int64_t hint) { BlockDriver *drv =3D bs->drv; =20 + if (!drv) { + return -ENOMEDIUM; + } + /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */ if (bdrv_is_sg(bs)) return 0; @@ -3431,6 +3435,10 @@ int bdrv_change_backing_file(BlockDriverState *bs, BlockDriver *drv =3D bs->drv; int ret; =20 + if (!drv) { + return -ENOMEDIUM; + } + /* Backing file format doesn't make sense without a backing file */ if (backing_fmt && !backing_file) { return -EINVAL; @@ -3916,7 +3924,9 @@ int bdrv_has_zero_init_1(BlockDriverState *bs) =20 int bdrv_has_zero_init(BlockDriverState *bs) { - assert(bs->drv); + if (!bs->drv) { + return 0; + } =20 /* If BS is a copy on write image, it is initialized to the contents of the base image, which may not be zeroes. */ @@ -4245,6 +4255,10 @@ static int bdrv_inactivate_recurse(BlockDriverState = *bs, BdrvChild *child, *parent; int ret; =20 + if (!bs->drv) { + return -ENOMEDIUM; + } + if (!setting_flag && bs->drv->bdrv_inactivate) { ret =3D bs->drv->bdrv_inactivate(bs); if (ret < 0) { @@ -4780,6 +4794,9 @@ void bdrv_remove_aio_context_notifier(BlockDriverStat= e *bs, int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, void *cb_opaqu= e) { + if (!bs->drv) { + return -ENOMEDIUM; + } if (!bs->drv->bdrv_amend_options) { return -ENOTSUP; } diff --git a/block/io.c b/block/io.c index 3d5ef2cabe..4fdf93a014 100644 --- a/block/io.c +++ b/block/io.c @@ -853,6 +853,10 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriver= State *bs, =20 assert(!(flags & ~BDRV_REQ_MASK)); =20 + if (!drv) { + return -ENOMEDIUM; + } + if (drv->bdrv_co_preadv) { return drv->bdrv_co_preadv(bs, offset, bytes, qiov, flags); } @@ -894,6 +898,10 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDrive= rState *bs, =20 assert(!(flags & ~BDRV_REQ_MASK)); =20 + if (!drv) { + return -ENOMEDIUM; + } + if (drv->bdrv_co_pwritev) { ret =3D drv->bdrv_co_pwritev(bs, offset, bytes, qiov, flags & bs->supported_write_flags); @@ -945,6 +953,10 @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, u= int64_t offset, { BlockDriver *drv =3D bs->drv; =20 + if (!drv) { + return -ENOMEDIUM; + } + if (!drv->bdrv_co_pwritev_compressed) { return -ENOTSUP; } @@ -975,6 +987,10 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvC= hild *child, BDRV_REQUEST_MAX_BYTES); unsigned int progress =3D 0; =20 + if (!drv) { + return -ENOMEDIUM; + } + /* FIXME We cannot require callers to have write permissions when all = they * are doing is a read request. If we did things right, write permissi= ons * would be obtained anyway, but internally by the copy-on-read code. = As @@ -1291,6 +1307,10 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(Blo= ckDriverState *bs, bs->bl.request_alignment); int max_transfer =3D MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFF= ER); =20 + if (!drv) { + return -ENOMEDIUM; + } + assert(alignment % bs->bl.request_alignment =3D=3D 0); head =3D offset % alignment; tail =3D (offset + bytes) % alignment; @@ -1397,6 +1417,10 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChi= ld *child, uint64_t bytes_remaining =3D bytes; int max_transfer; =20 + if (!drv) { + return -ENOMEDIUM; + } + if (bdrv_has_readonly_bitmaps(bs)) { return -EPERM; } @@ -1863,6 +1887,8 @@ static int coroutine_fn bdrv_co_block_status(BlockDri= verState *bs, bytes =3D n; } =20 + /* Must be non-NULL or bdrv_getlength() would have failed */ + assert(bs->drv); if (!bs->drv->bdrv_co_get_block_status) { *pnum =3D bytes; ret =3D BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED; @@ -2373,6 +2399,12 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) } =20 BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK); + if (!bs->drv) { + /* bs->drv->bdrv_co_flush() might have ejected the BDS + * (even in case of apparent success) */ + ret =3D -ENOMEDIUM; + goto out; + } if (bs->drv->bdrv_co_flush_to_disk) { ret =3D bs->drv->bdrv_co_flush_to_disk(bs); } else if (bs->drv->bdrv_aio_flush) { @@ -2542,6 +2574,10 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *= bs, int64_t offset, num =3D max_pdiscard; } =20 + if (!bs->drv) { + ret =3D -ENOMEDIUM; + goto out; + } if (bs->drv->bdrv_co_pdiscard) { ret =3D bs->drv->bdrv_co_pdiscard(bs, offset, num); } else { diff --git a/block/qapi.c b/block/qapi.c index 7fa2437923..fc10f0a565 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -39,8 +39,14 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *bl= k, { ImageInfo **p_image_info; BlockDriverState *bs0; - BlockDeviceInfo *info =3D g_malloc0(sizeof(*info)); + BlockDeviceInfo *info; =20 + if (!bs->drv) { + error_setg(errp, "Block device %s is ejected", bs->node_name); + return NULL; + } + + info =3D g_malloc0(sizeof(*info)); info->file =3D g_strdup(bs->filename); info->ro =3D bs->read_only; info->drv =3D g_strdup(bs->drv->format_name); diff --git a/block/replication.c b/block/replication.c index 1c95d673ff..e41e293d2b 100644 --- a/block/replication.c +++ b/block/replication.c @@ -342,12 +342,24 @@ static void secondary_do_checkpoint(BDRVReplicationSt= ate *s, Error **errp) return; } =20 + if (!s->active_disk->bs->drv) { + error_setg(errp, "Active disk %s is ejected", + s->active_disk->bs->node_name); + return; + } + ret =3D s->active_disk->bs->drv->bdrv_make_empty(s->active_disk->bs); if (ret < 0) { error_setg(errp, "Cannot make active disk empty"); return; } =20 + if (!s->hidden_disk->bs->drv) { + error_setg(errp, "Hidden disk %s is ejected", + s->hidden_disk->bs->node_name); + return; + } + ret =3D s->hidden_disk->bs->drv->bdrv_make_empty(s->hidden_disk->bs); if (ret < 0) { error_setg(errp, "Cannot make hidden disk empty"); @@ -511,6 +523,9 @@ static void replication_start(ReplicationState *rs, Rep= licationMode mode, return; } =20 + /* Must be true, or the bdrv_getlength() calls would have failed */ + assert(s->active_disk->bs->drv && s->hidden_disk->bs->drv); + if (!s->active_disk->bs->drv->bdrv_make_empty || !s->hidden_disk->bs->drv->bdrv_make_empty) { error_setg(errp, diff --git a/block/vvfat.c b/block/vvfat.c index 0841cc42fc..a690595f2c 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2947,7 +2947,7 @@ static int do_commit(BDRVVVFATState* s) return ret; } =20 - if (s->qcow->bs->drv->bdrv_make_empty) { + if (s->qcow->bs->drv && s->qcow->bs->drv->bdrv_make_empty) { s->qcow->bs->drv->bdrv_make_empty(s->qcow->bs); } =20 diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 49bc89df38..44141f6243 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -337,6 +337,28 @@ $QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io =20 # Can't repair this yet (TODO: We can just deallocate the cluster) =20 +echo +echo '=3D=3D=3D Discarding with an unaligned refblock =3D=3D=3D' +echo + +_make_test_img 64M + +$QEMU_IO -c "write 0 128k" "$TEST_IMG" | _filter_qemu_io +# Make our refblock unaligned +poke_file "$TEST_IMG" "$(($rt_offset))" "\x00\x00\x00\x00\x00\x00\x2a\x00" +# Now try to discard something that will be submitted as two requests +# (main part + tail) +$QEMU_IO -c "discard 0 65537" "$TEST_IMG" + +echo '--- Repairing ---' +# Fails the first repair because the corruption prevents the check +# function from double-checking +# (Using -q for the first invocation, because otherwise the +# double-check error message appears above the summary for some +# reason -- so let's just hide the summary) +_check_test_img -q -r all +_check_test_img -r all + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index c583076808..07dfdcac99 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -317,4 +317,35 @@ discard 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 u= naligned (guest offset: 0); further corruption events will be suppressed write failed: Input/output error + +=3D=3D=3D Discarding with an unaligned refblock =3D=3D=3D + +Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 +wrote 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftabl= e index: 0); further corruption events will be suppressed +qcow2_free_clusters failed: Input/output error +discard failed: No medium found +--- Repairing --- +ERROR refcount block 0 is not cluster aligned; refcount table entry corrup= ted +qcow2: Marking image as corrupt: Refblock offset 0x2a00 unaligned (reftabl= e index: 0); further corruption events will be suppressed +Can't get refcount for cluster 0: Input/output error +Can't get refcount for cluster 1: Input/output error +Can't get refcount for cluster 2: Input/output error +Can't get refcount for cluster 3: Input/output error +Can't get refcount for cluster 4: Input/output error +Can't get refcount for cluster 5: Input/output error +Can't get refcount for cluster 6: Input/output error +Rebuilding refcount structure +Repairing cluster 1 refcount=3D1 reference=3D0 +qemu-img: Check failed: No medium found +Leaked cluster 1 refcount=3D1 reference=3D0 +Repairing cluster 1 refcount=3D1 reference=3D0 +The following inconsistencies were found and repaired: + + 1 leaked clusters + 0 corruptions + +Double checking the fixed image now... +No errors were found on the image. *** done --=20 2.13.6 From nobody Wed May 8 12:57:40 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510346150902225.11751164414204; Fri, 10 Nov 2017 12:35:50 -0800 (PST) Received: from localhost ([::1]:43401 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDG1h-0004W5-1Z for importer@patchew.org; Fri, 10 Nov 2017 15:35:45 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54953) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDFxo-0001S4-Td for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eDFxm-0004Hw-6E for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:50026) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eDFxi-0004G7-EB; Fri, 10 Nov 2017 15:31:38 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 972F9C04D28B; Fri, 10 Nov 2017 20:31:37 +0000 (UTC) Received: from localhost (ovpn-204-126.brq.redhat.com [10.40.204.126]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 507EE5D978; Fri, 10 Nov 2017 20:31:34 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Fri, 10 Nov 2017 21:31:10 +0100 Message-Id: <20171110203111.7666-5-mreitz@redhat.com> In-Reply-To: <20171110203111.7666-1-mreitz@redhat.com> References: <20171110203111.7666-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Fri, 10 Nov 2017 20:31:37 +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] [PATCH for-2.11 4/5] qcow2: Add bounds check to get_refblock_offset() 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 , John Snow , Alberto Garcia , qemu-devel@nongnu.org, Max Reitz 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" Reported-by: R. Nageswara Sastry Buglink: https://bugs.launchpad.net/qemu/+bug/1728661 Signed-off-by: Max Reitz Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake --- block/qcow2.h | 6 ------ block/qcow2-refcount.c | 26 +++++++++++++++++++++++++- tests/qemu-iotests/060 | 46 ++++++++++++++++++++++++++++++++++++++++++= ++++ tests/qemu-iotests/060.out | 22 ++++++++++++++++++++++ 4 files changed, 93 insertions(+), 7 deletions(-) diff --git a/block/qcow2.h b/block/qcow2.h index 782a206ecb..6f0ff15dd0 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -527,12 +527,6 @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, u= int64_t offset) return offset >> (s->refcount_block_bits + s->cluster_bits); } =20 -static inline uint64_t get_refblock_offset(BDRVQcow2State *s, uint64_t off= set) -{ - uint32_t index =3D offset_to_reftable_index(s, offset); - return s->refcount_table[index] & REFT_OFFSET_MASK; -} - /* qcow2.c functions */ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, int64_t sector_num, int nb_sectors); diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 60b8eef3e8..3de1ab51ba 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -3077,16 +3077,40 @@ done: return ret; } =20 +static int64_t get_refblock_offset(BlockDriverState *bs, uint64_t offset) +{ + BDRVQcow2State *s =3D bs->opaque; + uint32_t index =3D offset_to_reftable_index(s, offset); + int64_t covering_refblock_offset =3D 0; + + if (index < s->refcount_table_size) { + covering_refblock_offset =3D s->refcount_table[index] & REFT_OFFSE= T_MASK; + } + if (!covering_refblock_offset) { + qcow2_signal_corruption(bs, true, -1, -1, "Refblock at %#" PRIx64 = " is " + "not covered by the refcount structures", + offset); + return -EIO; + } + + return covering_refblock_offset; +} + static int qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs) { BDRVQcow2State *s =3D bs->opaque; - uint64_t refblock_offs =3D get_refblock_offset(s, discard_block_offs); + int64_t refblock_offs; uint64_t cluster_index =3D discard_block_offs >> s->cluster_bits; uint32_t block_index =3D cluster_index & (s->refcount_block_size - 1); void *refblock; int ret; =20 + refblock_offs =3D get_refblock_offset(bs, discard_block_offs); + if (refblock_offs < 0) { + return refblock_offs; + } + assert(discard_block_offs !=3D 0); =20 ret =3D qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs, diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 44141f6243..c230696b3a 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -359,6 +359,52 @@ echo '--- Repairing ---' _check_test_img -q -r all _check_test_img -r all =20 +echo +echo "=3D=3D=3D Discarding an out-of-bounds refblock =3D=3D=3D" +echo + +_make_test_img 64M + +# Pretend there's a refblock really up high +poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\xff\xff\xff\x00\x00\x00\x0= 0" +# Let's try to shrink the qcow2 image so that the block driver tries +# to discard that refblock (and see what happens!) +$QEMU_IMG resize --shrink "$TEST_IMG" 32M + +echo '--- Checking and retrying ---' +# Image should not be resized +_img_info | grep 'virtual size' +# But it should pass this check, because the "partial" resize has +# already overwritten refblocks past the end +_check_test_img -r all +# So let's try again +$QEMU_IMG resize --shrink "$TEST_IMG" 32M +_img_info | grep 'virtual size' + +echo +echo "=3D=3D=3D Discarding a non-covered in-bounds refblock =3D=3D=3D" +echo + +IMGOPTS=3D'refcount_bits=3D1' _make_test_img 64M + +# Pretend there's a refblock somewhere where there is no refblock to +# cover it (but the covering refblock has a valid index in the +# reftable) +# Every refblock covers 65536 * 8 * 65536 =3D 32 GB, so we have to point +# to 0x10_0000_0000 (64G) to point to the third refblock +poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x0= 0" +$QEMU_IMG resize --shrink "$TEST_IMG" 32M + +echo '--- Checking and retrying ---' +# Image should not be resized +_img_info | grep 'virtual size' +# But it should pass this check, because the "partial" resize has +# already overwritten refblocks past the end +_check_test_img -r all +# So let's try again +$QEMU_IMG resize --shrink "$TEST_IMG" 32M +_img_info | grep 'virtual size' + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 07dfdcac99..358e54cdc9 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -348,4 +348,26 @@ The following inconsistencies were found and repaired: =20 Double checking the fixed image now... No errors were found on the image. + +=3D=3D=3D Discarding an out-of-bounds refblock =3D=3D=3D + +Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 +qcow2: Marking image as corrupt: Refblock at 0xffffff00000000 is not cover= ed by the refcount structures; further corruption events will be suppressed +qemu-img: Failed to discard unused refblocks: Input/output error +--- Checking and retrying --- +virtual size: 64M (67108864 bytes) +No errors were found on the image. +Image resized. +virtual size: 32M (33554432 bytes) + +=3D=3D=3D Discarding a non-covered in-bounds refblock =3D=3D=3D + +Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 +qcow2: Marking image as corrupt: Refblock at 0x1000000000 is not covered b= y the refcount structures; further corruption events will be suppressed +qemu-img: Failed to discard unused refblocks: Input/output error +--- Checking and retrying --- +virtual size: 64M (67108864 bytes) +No errors were found on the image. +Image resized. +virtual size: 32M (33554432 bytes) *** done --=20 2.13.6 From nobody Wed May 8 12:57:40 2024 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510346044447280.10477809724864; Fri, 10 Nov 2017 12:34:04 -0800 (PST) Received: from localhost ([::1]:43389 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDFzu-0002rn-Af for importer@patchew.org; Fri, 10 Nov 2017 15:33:54 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54982) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eDFxr-0001Vp-GA for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eDFxq-0004Kg-De for qemu-devel@nongnu.org; Fri, 10 Nov 2017 15:31:47 -0500 Received: from mx1.redhat.com ([209.132.183.28]:47768) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eDFxl-0004Hj-F1; Fri, 10 Nov 2017 15:31:41 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9B8AB7EAB1; Fri, 10 Nov 2017 20:31:40 +0000 (UTC) Received: from localhost (ovpn-204-126.brq.redhat.com [10.40.204.126]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 23B3662669; Fri, 10 Nov 2017 20:31:39 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Fri, 10 Nov 2017 21:31:11 +0100 Message-Id: <20171110203111.7666-6-mreitz@redhat.com> In-Reply-To: <20171110203111.7666-1-mreitz@redhat.com> References: <20171110203111.7666-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Fri, 10 Nov 2017 20:31:40 +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] [PATCH for-2.11 5/5] qcow2: Refuse to get unaligned offsets from cache 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 , John Snow , Alberto Garcia , qemu-devel@nongnu.org, Max Reitz 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" Instead of using an assertion, it is better to emit a corruption event here. Checking all offsets for correct alignment can be tedious and it is easily possible to forget to do so. qcow2_cache_do_get() is a function every L2 and refblock access has to go through, so this is a good central point to add such a check. And for good measure, let us also add an assertion that the offset is non-zero. Making this a corruption event is not feasible, because a zero offset usually means something special (such as the cluster is unused), so all callers should be checking this anyway. If they do not, it is their fault, hence the assertion here. Signed-off-by: Max Reitz Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake --- block/qcow2-cache.c | 21 +++++++++++++++++++++ tests/qemu-iotests/060 | 21 +++++++++++++++++++++ tests/qemu-iotests/060.out | 29 +++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 75746a7f43..a5baaba0ff 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -62,6 +62,18 @@ static inline int qcow2_cache_get_table_idx(BlockDriverS= tate *bs, return idx; } =20 +static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cac= he *c) +{ + if (c =3D=3D s->refcount_block_cache) { + return "refcount block"; + } else if (c =3D=3D s->l2_table_cache) { + return "L2 table"; + } else { + /* Do not abort, because this is not critical */ + return "unknown"; + } +} + static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c, int i, int num_tables) { @@ -314,9 +326,18 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qc= ow2Cache *c, uint64_t min_lru_counter =3D UINT64_MAX; int min_lru_index =3D -1; =20 + assert(offset !=3D 0); + trace_qcow2_cache_get(qemu_coroutine_self(), c =3D=3D s->l2_table_cach= e, offset, read_from_disk); =20 + if (offset_into_cluster(s, offset)) { + qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %= s " + "cache: Offset %#" PRIx64 " is unaligned", + qcow2_cache_get_name(s, c), offset); + return -EIO; + } + /* Check if the table is already cached */ i =3D lookup_index =3D (offset / s->cluster_size * 4) % c->size; do { diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index c230696b3a..1eca09417b 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -405,6 +405,27 @@ _check_test_img -r all $QEMU_IMG resize --shrink "$TEST_IMG" 32M _img_info | grep 'virtual size' =20 +echo +echo "=3D=3D=3D Discarding a refblock covered by an unaligned refblock =3D= =3D=3D" +echo + +IMGOPTS=3D'refcount_bits=3D1' _make_test_img 64M + +# Same as above +poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x0= 0" +# But now we actually "create" an unaligned third refblock +poke_file "$TEST_IMG" "$(($rt_offset+16))" "\x00\x00\x00\x00\x00\x00\x02\x= 00" +$QEMU_IMG resize --shrink "$TEST_IMG" 32M + +echo '--- Repairing ---' +# Fails the first repair because the corruption prevents the check +# function from double-checking +# (Using -q for the first invocation, because otherwise the +# double-check error message appears above the summary for some +# reason -- so let's just hide the summary) +_check_test_img -q -r all +_check_test_img -r all + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index 358e54cdc9..56f5eb15d8 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -370,4 +370,33 @@ virtual size: 64M (67108864 bytes) No errors were found on the image. Image resized. virtual size: 32M (33554432 bytes) + +=3D=3D=3D Discarding a refblock covered by an unaligned refblock =3D=3D=3D + +Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 +qcow2: Marking image as corrupt: Cannot get entry from refcount block cach= e: Offset 0x200 is unaligned; further corruption events will be suppressed +qemu-img: Failed to discard unused refblocks: Input/output error +--- Repairing --- +Repairing refcount block 1 is outside image +ERROR refcount block 2 is not cluster aligned; refcount table entry corrup= ted +qcow2: Marking image as corrupt: Refblock offset 0x200 unaligned (reftable= index: 0x2); further corruption events will be suppressed +Can't get refcount for cluster 1048576: Input/output error +Rebuilding refcount structure +Repairing cluster 1 refcount=3D1 reference=3D0 +Repairing cluster 2 refcount=3D1 reference=3D0 +Repairing cluster 1048576 refcount=3D1 reference=3D0 +qemu-img: Check failed: No medium found +Leaked cluster 1 refcount=3D1 reference=3D0 +Leaked cluster 2 refcount=3D1 reference=3D0 +Leaked cluster 1048576 refcount=3D1 reference=3D0 +Repairing cluster 1 refcount=3D1 reference=3D0 +Repairing cluster 2 refcount=3D1 reference=3D0 +Repairing cluster 1048576 refcount=3D1 reference=3D0 +The following inconsistencies were found and repaired: + + 3 leaked clusters + 0 corruptions + +Double checking the fixed image now... +No errors were found on the image. *** done --=20 2.13.6