From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) client-ip=209.51.188.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; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 154895754835112.369656544688041; Thu, 31 Jan 2019 09:59:08 -0800 (PST) Received: from localhost ([127.0.0.1]:58356 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGc5-0007wE-5H for importer@patchew.org; Thu, 31 Jan 2019 12:58:57 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51246) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZL-0005ku-7Z for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZK-00055X-2E for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:07 -0500 Received: from mx1.redhat.com ([209.132.183.28]:17347) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZF-0004zJ-Qb; Thu, 31 Jan 2019 12:56:03 -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 21B90A786E; Thu, 31 Jan 2019 17:55:59 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id D09295D9D6; Thu, 31 Jan 2019 17:55:57 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:39 +0100 Message-Id: <20190131175549.11691-2-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.30]); Thu, 31 Jan 2019 17:55:59 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 01/11] qcow2: Extend spec for external data files 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This adds external data file to the qcow2 spec as a new incompatible feature. Signed-off-by: Kevin Wolf --- docs/interop/qcow2.txt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index fb5cb47245..90af0d02e5 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -97,7 +97,17 @@ in the description of a field. be written to (unless for regaining consistency). =20 - Bits 2-63: Reserved (set to 0) + Bit 2: External data file. If this bit is set, an + external data file name header extension m= ust + be present as well. Guest clusters are then + stored in the external data file. For such + images, clusters in the external data file= are + not refcounted. The offset field in the + Standard Cluster Descriptor must match the + guest offset and neither compressed cluste= rs + nor internal snapshots are supported. + + Bits 3-63: Reserved (set to 0) =20 80 - 87: compatible_features Bitmask of compatible features. An implementation can @@ -148,6 +158,7 @@ be stored. Each extension has a structure like the foll= owing: 0x6803f857 - Feature name table 0x23852875 - Bitmaps extension 0x0537be77 - Full disk encryption header pointer + 0x44415441 - External data file name other - Unknown header extension, can be safe= ly ignored =20 @@ -450,8 +461,10 @@ Standard Cluster Descriptor: 1 - 8: Reserved (set to 0) =20 9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a - cluster boundary. If the offset is 0, the cluster is - unallocated. + cluster boundary. If the offset is 0 and bit 63 is cle= ar, + the cluster is unallocated. The offset may only be 0 w= ith + bit 63 set (indicating a host cluster offset of 0) whe= n an + external data file is used. =20 56 - 61: Reserved (set to 0) =20 --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548957790413477.20263850472645; Thu, 31 Jan 2019 10:03:10 -0800 (PST) Received: from localhost ([127.0.0.1]:58428 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGg5-00035k-MU for importer@patchew.org; Thu, 31 Jan 2019 13:03:05 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51277) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZM-0005ls-5P for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZK-00055m-I5 for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:07 -0500 Received: from mx1.redhat.com ([209.132.183.28]:59530) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZF-0004zk-KA; Thu, 31 Jan 2019 12:56:01 -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 BACE6124D29; Thu, 31 Jan 2019 17:56:00 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6D34A5D9D6; Thu, 31 Jan 2019 17:55:59 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:40 +0100 Message-Id: <20190131175549.11691-3-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.39]); Thu, 31 Jan 2019 17:56:00 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 02/11] qcow2: Basic definitions for external data files 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This adds basic constants, struct fields and helper function for external data file support to the implementation. QCOW2_INCOMPAT_MASK is not updated yet so that opening images with an external data file still fails (we don't handle them correctly yet). Signed-off-by: Kevin Wolf --- block/qcow2.h | 18 ++++++++++++++---- block/qcow2.c | 9 +++++++++ tests/qemu-iotests/031.out | 8 ++++---- tests/qemu-iotests/036.out | 4 ++-- tests/qemu-iotests/061.out | 14 +++++++------- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/block/qcow2.h b/block/qcow2.h index 32cce9eee2..a242a43fe7 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -197,10 +197,12 @@ enum { =20 /* Incompatible feature bits */ enum { - QCOW2_INCOMPAT_DIRTY_BITNR =3D 0, - QCOW2_INCOMPAT_CORRUPT_BITNR =3D 1, - QCOW2_INCOMPAT_DIRTY =3D 1 << QCOW2_INCOMPAT_DIRTY_BITNR, - QCOW2_INCOMPAT_CORRUPT =3D 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, + QCOW2_INCOMPAT_DIRTY_BITNR =3D 0, + QCOW2_INCOMPAT_CORRUPT_BITNR =3D 1, + QCOW2_INCOMPAT_DATA_FILE_BITNR =3D 2, + QCOW2_INCOMPAT_DIRTY =3D 1 << QCOW2_INCOMPAT_DIRTY_BITNR, + QCOW2_INCOMPAT_CORRUPT =3D 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, + QCOW2_INCOMPAT_DATA_FILE =3D 1 << QCOW2_INCOMPAT_DATA_FILE_BITN= R, =20 QCOW2_INCOMPAT_MASK =3D QCOW2_INCOMPAT_DIRTY | QCOW2_INCOMPAT_CORRUPT, @@ -340,6 +342,8 @@ typedef struct BDRVQcow2State { =20 CoQueue compress_wait_queue; int nb_compress_threads; + + BdrvChild *data_file; } BDRVQcow2State; =20 typedef struct Qcow2COWRegion { @@ -457,6 +461,12 @@ typedef enum QCow2MetadataOverlap { =20 #define REFT_OFFSET_MASK 0xfffffffffffffe00ULL =20 +static inline bool has_data_file(BlockDriverState *bs) +{ + BDRVQcow2State *s =3D bs->opaque; + return (s->data_file !=3D bs->file); +} + static inline int64_t start_of_cluster(BDRVQcow2State *s, int64_t offset) { return offset & ~(s->cluster_size - 1); diff --git a/block/qcow2.c b/block/qcow2.c index 8c91b92865..2b81cf839d 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -73,6 +73,7 @@ typedef struct { #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 +#define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441 =20 static int coroutine_fn qcow2_co_preadv_compressed(BlockDriverState *bs, @@ -1440,6 +1441,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverStat= e *bs, QDict *options, goto fail; } =20 + /* TODO Open external data file */ + s->data_file =3D bs->file; + /* qcow2_read_extension may have set up the crypto context * if the crypt method needs a header region, some methods * don't need header extensions, so must check here @@ -2426,6 +2430,11 @@ int qcow2_update_header(BlockDriverState *bs) .bit =3D QCOW2_INCOMPAT_CORRUPT_BITNR, .name =3D "corrupt bit", }, + { + .type =3D QCOW2_FEAT_TYPE_INCOMPATIBLE, + .bit =3D QCOW2_INCOMPAT_DATA_FILE_BITNR, + .name =3D "external data file", + }, { .type =3D QCOW2_FEAT_TYPE_COMPATIBLE, .bit =3D QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR, diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out index 7f5050b816..68a74d03b9 100644 --- a/tests/qemu-iotests/031.out +++ b/tests/qemu-iotests/031.out @@ -117,7 +117,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 Header extension: @@ -150,7 +150,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 Header extension: @@ -164,7 +164,7 @@ No errors were found on the image. =20 magic 0x514649fb version 3 -backing_file_offset 0x148 +backing_file_offset 0x178 backing_file_size 0x17 cluster_bits 16 size 67108864 @@ -188,7 +188,7 @@ data 'host_device' =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 Header extension: diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index 9b009b8c15..e489b44386 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -58,7 +58,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 =20 @@ -86,7 +86,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 *** done diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 183f7dd690..758284011b 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -26,7 +26,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 magic 0x514649fb @@ -84,7 +84,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 magic 0x514649fb @@ -144,7 +144,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 ERROR cluster 5 refcount=3D0 reference=3D1 @@ -199,7 +199,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 magic 0x514649fb @@ -268,7 +268,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 read 65536/65536 bytes at offset 44040192 @@ -306,7 +306,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 ERROR cluster 5 refcount=3D0 reference=3D1 @@ -335,7 +335,7 @@ header_length 104 =20 Header extension: magic 0x6803f857 -length 144 +length 192 data =20 read 131072/131072 bytes at offset 0 --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 154895856365690.36746743500794; Thu, 31 Jan 2019 10:16:03 -0800 (PST) Received: from localhost ([127.0.0.1]:58677 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGsR-000683-1z for importer@patchew.org; Thu, 31 Jan 2019 13:15:51 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51323) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZO-0005oH-71 for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:13 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZM-00056w-JK for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:10 -0500 Received: from mx1.redhat.com ([209.132.183.28]:31122) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZH-00052O-Q4; Thu, 31 Jan 2019 12:56:03 -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 69B71C0C49EA; Thu, 31 Jan 2019 17:56:02 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0AA5A5D9D6; Thu, 31 Jan 2019 17:56:00 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:41 +0100 Message-Id: <20190131175549.11691-4-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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]); Thu, 31 Jan 2019 17:56:02 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 03/11] qcow2: Pass bs to qcow2_get_cluster_type() 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Kevin Wolf --- block/qcow2.h | 3 ++- block/qcow2-cluster.c | 37 +++++++++++++++++++------------------ block/qcow2-refcount.c | 10 +++++----- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/block/qcow2.h b/block/qcow2.h index a242a43fe7..2cb763bf11 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -508,7 +508,8 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2St= ate *s) return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits); } =20 -static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry) +static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs, + uint64_t l2_entry) { if (l2_entry & QCOW_OFLAG_COMPRESSED) { return QCOW2_CLUSTER_COMPRESSED; diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 30eca26c47..7c86e3f205 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -377,8 +377,8 @@ fail: * as contiguous. (This allows it, for example, to stop at the first compr= essed * cluster which may require a different handling) */ -static int count_contiguous_clusters(int nb_clusters, int cluster_size, - uint64_t *l2_slice, uint64_t stop_flags) +static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters, + int cluster_size, uint64_t *l2_slice, uint64_t stop_flags) { int i; QCow2ClusterType first_cluster_type; @@ -391,7 +391,7 @@ static int count_contiguous_clusters(int nb_clusters, i= nt cluster_size, } =20 /* must be allocated */ - first_cluster_type =3D qcow2_get_cluster_type(first_entry); + first_cluster_type =3D qcow2_get_cluster_type(bs, first_entry); assert(first_cluster_type =3D=3D QCOW2_CLUSTER_NORMAL || first_cluster_type =3D=3D QCOW2_CLUSTER_ZERO_ALLOC); =20 @@ -409,7 +409,8 @@ static int count_contiguous_clusters(int nb_clusters, i= nt cluster_size, * Checks how many consecutive unallocated clusters in a given L2 * slice have the same cluster type. */ -static int count_contiguous_clusters_unallocated(int nb_clusters, +static int count_contiguous_clusters_unallocated(BlockDriverState *bs, + int nb_clusters, uint64_t *l2_slice, QCow2ClusterType wanted_t= ype) { @@ -419,7 +420,7 @@ static int count_contiguous_clusters_unallocated(int nb= _clusters, wanted_type =3D=3D QCOW2_CLUSTER_UNALLOCATED); for (i =3D 0; i < nb_clusters; i++) { uint64_t entry =3D be64_to_cpu(l2_slice[i]); - QCow2ClusterType type =3D qcow2_get_cluster_type(entry); + QCow2ClusterType type =3D qcow2_get_cluster_type(bs, entry); =20 if (type !=3D wanted_type) { break; @@ -592,7 +593,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint= 64_t offset, * true */ assert(nb_clusters <=3D INT_MAX); =20 - type =3D qcow2_get_cluster_type(*cluster_offset); + type =3D qcow2_get_cluster_type(bs, *cluster_offset); if (s->qcow_version < 3 && (type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN || type =3D=3D QCOW2_CLUSTER_ZERO_ALLOC)) { qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry foun= d" @@ -610,14 +611,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, ui= nt64_t offset, case QCOW2_CLUSTER_ZERO_PLAIN: case QCOW2_CLUSTER_UNALLOCATED: /* how many empty clusters ? */ - c =3D count_contiguous_clusters_unallocated(nb_clusters, + c =3D count_contiguous_clusters_unallocated(bs, nb_clusters, &l2_slice[l2_index], typ= e); *cluster_offset =3D 0; break; case QCOW2_CLUSTER_ZERO_ALLOC: case QCOW2_CLUSTER_NORMAL: /* how many allocated clusters ? */ - c =3D count_contiguous_clusters(nb_clusters, s->cluster_size, + c =3D count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_ZERO= ); *cluster_offset &=3D L2E_OFFSET_MASK; if (offset_into_cluster(s, *cluster_offset)) { @@ -1010,14 +1011,14 @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs= , QCowL2Meta *m) * write, but require COW to be performed (this includes yet unallocated s= pace, * which must copy from the backing file) */ -static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters, +static int count_cow_clusters(BlockDriverState *bs, int nb_clusters, uint64_t *l2_slice, int l2_index) { int i; =20 for (i =3D 0; i < nb_clusters; i++) { uint64_t l2_entry =3D be64_to_cpu(l2_slice[l2_index + i]); - QCow2ClusterType cluster_type =3D qcow2_get_cluster_type(l2_entry); + QCow2ClusterType cluster_type =3D qcow2_get_cluster_type(bs, l2_en= try); =20 switch(cluster_type) { case QCOW2_CLUSTER_NORMAL: @@ -1162,7 +1163,7 @@ static int handle_copied(BlockDriverState *bs, uint64= _t guest_offset, cluster_offset =3D be64_to_cpu(l2_slice[l2_index]); =20 /* Check how many clusters are already allocated and don't need COW */ - if (qcow2_get_cluster_type(cluster_offset) =3D=3D QCOW2_CLUSTER_NORMAL + if (qcow2_get_cluster_type(bs, cluster_offset) =3D=3D QCOW2_CLUSTER_NO= RMAL && (cluster_offset & QCOW_OFLAG_COPIED)) { /* If a specific host_offset is required, check it */ @@ -1186,7 +1187,7 @@ static int handle_copied(BlockDriverState *bs, uint64= _t guest_offset, =20 /* We keep all QCOW_OFLAG_COPIED clusters */ keep_clusters =3D - count_contiguous_clusters(nb_clusters, s->cluster_size, + count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO); assert(keep_clusters <=3D nb_clusters); @@ -1321,7 +1322,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_= t guest_offset, if (entry & QCOW_OFLAG_COMPRESSED) { nb_clusters =3D 1; } else { - nb_clusters =3D count_cow_clusters(s, nb_clusters, l2_slice, l2_in= dex); + nb_clusters =3D count_cow_clusters(bs, nb_clusters, l2_slice, l2_i= ndex); } =20 /* This function is only called when there were no non-COW clusters, s= o if @@ -1329,7 +1330,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_= t guest_offset, * wrong with our code. */ assert(nb_clusters > 0); =20 - if (qcow2_get_cluster_type(entry) =3D=3D QCOW2_CLUSTER_ZERO_ALLOC && + if (qcow2_get_cluster_type(bs, entry) =3D=3D QCOW2_CLUSTER_ZERO_ALLOC = && (entry & QCOW_OFLAG_COPIED) && (!*host_offset || start_of_cluster(s, *host_offset) =3D=3D (entry & L2E_OFFSET_MASK= ))) @@ -1349,7 +1350,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_= t guest_offset, * would be fine, too, but count_cow_clusters() above has limited * nb_clusters already to a range of COW clusters */ preallocated_nb_clusters =3D - count_contiguous_clusters(nb_clusters, s->cluster_size, + count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_COPI= ED); assert(preallocated_nb_clusters > 0); =20 @@ -1613,7 +1614,7 @@ static int discard_in_l2_slice(BlockDriverState *bs, = uint64_t offset, * If full_discard is true, the sector should not read back as zer= oes, * but rather fall through to the backing file. */ - switch (qcow2_get_cluster_type(old_l2_entry)) { + switch (qcow2_get_cluster_type(bs, old_l2_entry)) { case QCOW2_CLUSTER_UNALLOCATED: if (full_discard || !bs->backing) { continue; @@ -1726,7 +1727,7 @@ static int zero_in_l2_slice(BlockDriverState *bs, uin= t64_t offset, * Minimize L2 changes if the cluster already reads back as * zeroes with correct allocation. */ - cluster_type =3D qcow2_get_cluster_type(old_offset); + cluster_type =3D qcow2_get_cluster_type(bs, old_offset); if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN || (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) { continue; @@ -1868,7 +1869,7 @@ static int expand_zero_clusters_in_l1(BlockDriverStat= e *bs, uint64_t *l1_table, uint64_t l2_entry =3D be64_to_cpu(l2_slice[j]); int64_t offset =3D l2_entry & L2E_OFFSET_MASK; QCow2ClusterType cluster_type =3D - qcow2_get_cluster_type(l2_entry); + qcow2_get_cluster_type(bs, l2_entry); =20 if (cluster_type !=3D QCOW2_CLUSTER_ZERO_PLAIN && cluster_type !=3D QCOW2_CLUSTER_ZERO_ALLOC) { diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 6f13d470d3..05e7974d7e 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1157,7 +1157,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs, ui= nt64_t l2_entry, { BDRVQcow2State *s =3D bs->opaque; =20 - switch (qcow2_get_cluster_type(l2_entry)) { + switch (qcow2_get_cluster_type(bs, l2_entry)) { case QCOW2_CLUSTER_COMPRESSED: { int nb_csectors; @@ -1300,7 +1300,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *= bs, entry &=3D ~QCOW_OFLAG_COPIED; offset =3D entry & L2E_OFFSET_MASK; =20 - switch (qcow2_get_cluster_type(entry)) { + switch (qcow2_get_cluster_type(bs, entry)) { case QCOW2_CLUSTER_COMPRESSED: nb_csectors =3D ((entry >> s->csize_shift) & s->csize_mask) + 1; @@ -1582,7 +1582,7 @@ static int check_refcounts_l2(BlockDriverState *bs, B= drvCheckResult *res, for(i =3D 0; i < s->l2_size; i++) { l2_entry =3D be64_to_cpu(l2_table[i]); =20 - switch (qcow2_get_cluster_type(l2_entry)) { + switch (qcow2_get_cluster_type(bs, l2_entry)) { case QCOW2_CLUSTER_COMPRESSED: /* Compressed clusters don't have QCOW_OFLAG_COPIED */ if (l2_entry & QCOW_OFLAG_COPIED) { @@ -1633,7 +1633,7 @@ static int check_refcounts_l2(BlockDriverState *bs, B= drvCheckResult *res, =20 /* Correct offsets are cluster aligned */ if (offset_into_cluster(s, offset)) { - if (qcow2_get_cluster_type(l2_entry) =3D=3D + if (qcow2_get_cluster_type(bs, l2_entry) =3D=3D QCOW2_CLUSTER_ZERO_ALLOC) { fprintf(stderr, "%s offset=3D%" PRIx64 ": Preallocated= zero " @@ -1868,7 +1868,7 @@ static int check_oflag_copied(BlockDriverState *bs, B= drvCheckResult *res, for (j =3D 0; j < s->l2_size; j++) { uint64_t l2_entry =3D be64_to_cpu(l2_table[j]); uint64_t data_offset =3D l2_entry & L2E_OFFSET_MASK; - QCow2ClusterType cluster_type =3D qcow2_get_cluster_type(l2_en= try); + QCow2ClusterType cluster_type =3D qcow2_get_cluster_type(bs, l= 2_entry); =20 if (cluster_type =3D=3D QCOW2_CLUSTER_NORMAL || cluster_type =3D=3D QCOW2_CLUSTER_ZERO_ALLOC) { --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548958237668556.2580066814131; Thu, 31 Jan 2019 10:10:37 -0800 (PST) Received: from localhost ([127.0.0.1]:58541 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGnG-0000wL-H5 for importer@patchew.org; Thu, 31 Jan 2019 13:10:30 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51291) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZM-0005mh-Va for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZL-00056Q-DC for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:08 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57350) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZJ-00053v-74; Thu, 31 Jan 2019 12:56:05 -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 078608BA02; Thu, 31 Jan 2019 17:56:04 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9643C5D9D6; Thu, 31 Jan 2019 17:56:02 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:42 +0100 Message-Id: <20190131175549.11691-5-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.25]); Thu, 31 Jan 2019 17:56:04 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 04/11] qcow2: Prepare qcow2_get_cluster_type() for external data file 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Kevin Wolf --- block/qcow2.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/block/qcow2.h b/block/qcow2.h index 2cb763bf11..b17bd502f5 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -519,7 +519,15 @@ static inline QCow2ClusterType qcow2_get_cluster_type(= BlockDriverState *bs, } return QCOW2_CLUSTER_ZERO_PLAIN; } else if (!(l2_entry & L2E_OFFSET_MASK)) { - return QCOW2_CLUSTER_UNALLOCATED; + /* Offset 0 generally means unallocated, but it is ambiguous with + * external data files because 0 is a valid offset there. However,= all + * clusters in external data files always have refcount 1, so we c= an + * rely on QCOW_OFLAG_COPIED to disambiguate. */ + if (has_data_file(bs) && (l2_entry & QCOW_OFLAG_COPIED)) { + return QCOW2_CLUSTER_NORMAL; + } else { + return QCOW2_CLUSTER_UNALLOCATED; + } } else { return QCOW2_CLUSTER_NORMAL; } --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548958400530247.7596526770974; Thu, 31 Jan 2019 10:13:20 -0800 (PST) Received: from localhost ([127.0.0.1]:58615 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGpp-0003VD-Ad for importer@patchew.org; Thu, 31 Jan 2019 13:13:09 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51326) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZO-0005oK-7e for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:10 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZN-00057T-Dc for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:10 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57426) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZK-00055U-Ko; Thu, 31 Jan 2019 12:56:06 -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 9EABDAD886; Thu, 31 Jan 2019 17:56:05 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3596E5D982; Thu, 31 Jan 2019 17:56:04 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:43 +0100 Message-Id: <20190131175549.11691-6-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.28]); Thu, 31 Jan 2019 17:56:05 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 05/11] qcow2: Prepare count_contiguous_clusters() for external data file 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Offset 0 can be valid for normal (allocated) clusters now, so use qcow2_get_cluster_type() instead. Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 7c86e3f205..73ea0f99d6 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -386,12 +386,12 @@ static int count_contiguous_clusters(BlockDriverState= *bs, int nb_clusters, uint64_t first_entry =3D be64_to_cpu(l2_slice[0]); uint64_t offset =3D first_entry & mask; =20 - if (!offset) { + first_cluster_type =3D qcow2_get_cluster_type(bs, first_entry); + if (first_cluster_type =3D=3D QCOW2_CLUSTER_UNALLOCATED) { return 0; } =20 /* must be allocated */ - first_cluster_type =3D qcow2_get_cluster_type(bs, first_entry); assert(first_cluster_type =3D=3D QCOW2_CLUSTER_NORMAL || first_cluster_type =3D=3D QCOW2_CLUSTER_ZERO_ALLOC); =20 --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548957570145760.863195942217; Thu, 31 Jan 2019 09:59:30 -0800 (PST) Received: from localhost ([127.0.0.1]:58358 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGcW-0008Ld-V9 for importer@patchew.org; Thu, 31 Jan 2019 12:59:25 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51383) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZa-0005yY-HA for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:23 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZX-00059p-6c for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:22 -0500 Received: from mx1.redhat.com ([209.132.183.28]:52953) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZM-00056N-GI; Thu, 31 Jan 2019 12:56:08 -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 240182CD7EE; Thu, 31 Jan 2019 17:56:07 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id C87705D9D6; Thu, 31 Jan 2019 17:56:05 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:44 +0100 Message-Id: <20190131175549.11691-7-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.29]); Thu, 31 Jan 2019 17:56:07 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 06/11] qcow2: Don't assume 0 is an invalid cluster 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: kwolf@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" The cluster allocation code uses 0 as an invalid offset that is used in case of errors or as "offset not yet determined". With external data files, a host cluster offset of 0 becomes valid, though. Define a constant INV_OFFSET (which is not cluster aligned and will therefore never be a valid offset) that can be used for such purposes. This removes the additional host_offset =3D=3D 0 check that commit ff52aab2df5 introduced; the confusion between an invalid offset and (erroneous) allocation at offset 0 is removed with this change. Signed-off-by: Kevin Wolf --- block/qcow2.h | 2 ++ block/qcow2-cluster.c | 59 ++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/block/qcow2.h b/block/qcow2.h index b17bd502f5..1f87c45977 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -461,6 +461,8 @@ typedef enum QCow2MetadataOverlap { =20 #define REFT_OFFSET_MASK 0xfffffffffffffe00ULL =20 +#define INV_OFFSET (-1ULL) + static inline bool has_data_file(BlockDriverState *bs) { BDRVQcow2State *s =3D bs->opaque; diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 73ea0f99d6..4889c166e8 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1106,9 +1106,9 @@ static int handle_dependencies(BlockDriverState *bs, = uint64_t guest_offset, =20 /* * Checks how many already allocated clusters that don't require a copy on - * write there are at the given guest_offset (up to *bytes). If - * *host_offset is not zero, only physically contiguous clusters beginning= at - * this host offset are counted. + * write there are at the given guest_offset (up to *bytes). If *host_offs= et is + * not INV_OFFSET, only physically contiguous clusters beginning at this h= ost + * offset are counted. * * Note that guest_offset may not be cluster aligned. In this case, the * returned *host_offset points to exact byte referenced by guest_offset a= nd @@ -1140,8 +1140,8 @@ static int handle_copied(BlockDriverState *bs, uint64= _t guest_offset, trace_qcow2_handle_copied(qemu_coroutine_self(), guest_offset, *host_o= ffset, *bytes); =20 - assert(*host_offset =3D=3D 0 || offset_into_cluster(s, guest_offset) - =3D=3D offset_into_cluster(s, *host_offset= )); + assert(*host_offset =3D=3D INV_OFFSET || offset_into_cluster(s, guest_= offset) + =3D=3D offset_into_cluster(s, *host_= offset)); =20 /* * Calculate the number of clusters to look for. We stop at L2 slice @@ -1179,7 +1179,7 @@ static int handle_copied(BlockDriverState *bs, uint64= _t guest_offset, goto out; } =20 - if (*host_offset !=3D 0 && !offset_matches) { + if (*host_offset !=3D INV_OFFSET && !offset_matches) { *bytes =3D 0; ret =3D 0; goto out; @@ -1222,10 +1222,10 @@ out: * contain the number of clusters that have been allocated and are contigu= ous * in the image file. * - * If *host_offset is non-zero, it specifies the offset in the image file = at - * which the new clusters must start. *nb_clusters can be 0 on return in t= his - * case if the cluster at host_offset is already in use. If *host_offset is - * zero, the clusters can be allocated anywhere in the image file. + * If *host_offset is not INV_OFFSET, it specifies the offset in the image= file + * at which the new clusters must start. *nb_clusters can be 0 on return in + * this case if the cluster at host_offset is already in use. If *host_off= set + * is INV_OFFSET, the clusters can be allocated anywhere in the image file. * * *host_offset is updated to contain the offset into the image file at wh= ich * the first allocated cluster starts. @@ -1244,7 +1244,7 @@ static int do_alloc_cluster_offset(BlockDriverState *= bs, uint64_t guest_offset, =20 /* Allocate new clusters */ trace_qcow2_cluster_alloc_phys(qemu_coroutine_self()); - if (*host_offset =3D=3D 0) { + if (*host_offset =3D=3D INV_OFFSET) { int64_t cluster_offset =3D qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size); if (cluster_offset < 0) { @@ -1264,8 +1264,8 @@ static int do_alloc_cluster_offset(BlockDriverState *= bs, uint64_t guest_offset, =20 /* * Allocates new clusters for an area that either is yet unallocated or ne= eds a - * copy on write. If *host_offset is non-zero, clusters are only allocated= if - * the new allocation can match the specified host offset. + * copy on write. If *host_offset is not INV_OFFSET, clusters are only + * allocated if the new allocation can match the specified host offset. * * Note that guest_offset may not be cluster aligned. In this case, the * returned *host_offset points to exact byte referenced by guest_offset a= nd @@ -1293,7 +1293,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_= t guest_offset, int ret; bool keep_old_clusters =3D false; =20 - uint64_t alloc_cluster_offset =3D 0; + uint64_t alloc_cluster_offset =3D INV_OFFSET; =20 trace_qcow2_handle_alloc(qemu_coroutine_self(), guest_offset, *host_of= fset, *bytes); @@ -1332,7 +1332,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_= t guest_offset, =20 if (qcow2_get_cluster_type(bs, entry) =3D=3D QCOW2_CLUSTER_ZERO_ALLOC = && (entry & QCOW_OFLAG_COPIED) && - (!*host_offset || + (*host_offset =3D=3D INV_OFFSET || start_of_cluster(s, *host_offset) =3D=3D (entry & L2E_OFFSET_MASK= ))) { int preallocated_nb_clusters; @@ -1364,9 +1364,10 @@ static int handle_alloc(BlockDriverState *bs, uint64= _t guest_offset, =20 qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); =20 - if (!alloc_cluster_offset) { + if (alloc_cluster_offset =3D=3D INV_OFFSET) { /* Allocate, if necessary at a given offset in the image file */ - alloc_cluster_offset =3D start_of_cluster(s, *host_offset); + alloc_cluster_offset =3D *host_offset =3D=3D INV_OFFSET ? INV_OFFS= ET : + start_of_cluster(s, *host_offset); ret =3D do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_o= ffset, &nb_clusters); if (ret < 0) { @@ -1379,16 +1380,7 @@ static int handle_alloc(BlockDriverState *bs, uint64= _t guest_offset, return 0; } =20 - /* !*host_offset would overwrite the image header and is reserved = for - * "no host offset preferred". If 0 was a valid host offset, it'd - * trigger the following overlap check; do that now to avoid havin= g an - * invalid value in *host_offset. */ - if (!alloc_cluster_offset) { - ret =3D qcow2_pre_write_overlap_check(bs, 0, alloc_cluster_off= set, - nb_clusters * s->cluster_s= ize); - assert(ret < 0); - goto fail; - } + assert(alloc_cluster_offset !=3D INV_OFFSET); } =20 /* @@ -1480,14 +1472,14 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs= , uint64_t offset, again: start =3D offset; remaining =3D *bytes; - cluster_offset =3D 0; - *host_offset =3D 0; + cluster_offset =3D INV_OFFSET; + *host_offset =3D INV_OFFSET; cur_bytes =3D 0; *m =3D NULL; =20 while (true) { =20 - if (!*host_offset) { + if (*host_offset =3D=3D INV_OFFSET && cluster_offset !=3D INV_OFFS= ET) { *host_offset =3D start_of_cluster(s, cluster_offset); } =20 @@ -1495,7 +1487,10 @@ again: =20 start +=3D cur_bytes; remaining -=3D cur_bytes; - cluster_offset +=3D cur_bytes; + + if (cluster_offset !=3D INV_OFFSET) { + cluster_offset +=3D cur_bytes; + } =20 if (remaining =3D=3D 0) { break; @@ -1567,7 +1562,7 @@ again: =20 *bytes -=3D remaining; assert(*bytes > 0); - assert(*host_offset !=3D 0); + assert(*host_offset !=3D INV_OFFSET); =20 return 0; } --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548957766741872.4476215839929; Thu, 31 Jan 2019 10:02:46 -0800 (PST) Received: from localhost ([127.0.0.1]:58424 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGfi-0002nw-FC for importer@patchew.org; Thu, 31 Jan 2019 13:02:42 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51403) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZe-000626-15 for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZZ-0005Ar-9w for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:24 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57490) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZN-00057G-LV; Thu, 31 Jan 2019 12:56:09 -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 D6CA1AD8AB; Thu, 31 Jan 2019 17:56:08 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 659BE5D9D6; Thu, 31 Jan 2019 17:56:07 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:45 +0100 Message-Id: <20190131175549.11691-8-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.28]); Thu, 31 Jan 2019 17:56:08 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 07/11] qcow2: External file I/O 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This changes the qcow2 implementation to direct all guest data I/O to s->data_file rather than bs->file, while metadata I/O still uses bs->file. At the moment, this is still always the same, but soon we'll add options to set s->data_file to an external data file. Signed-off-by: Kevin Wolf --- block/qcow2.h | 2 +- block/qcow2-bitmap.c | 7 ++++--- block/qcow2-cache.c | 6 +++--- block/qcow2-cluster.c | 46 +++++++++++++++++++++++++++++++++++------- block/qcow2-refcount.c | 30 +++++++++++++++++++-------- block/qcow2-snapshot.c | 7 ++++--- block/qcow2.c | 39 +++++++++++++++++++++++++---------- 7 files changed, 101 insertions(+), 36 deletions(-) diff --git a/block/qcow2.h b/block/qcow2.h index 1f87c45977..c161970882 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -620,7 +620,7 @@ void qcow2_process_discards(BlockDriverState *bs, int r= et); int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t of= fset, int64_t size); int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t o= ffset, - int64_t size); + int64_t size, bool data_file); int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, void **refcount_table, int64_t *refcount_table_size, diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index b946301429..9f42ce13cb 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -778,7 +778,8 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow= 2BitmapList *bm_list, * directory in-place (actually, turn-off the extension), which is che= cked * in qcow2_check_metadata_overlap() */ ret =3D qcow2_pre_write_overlap_check( - bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_= size); + bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_= size, + false); if (ret < 0) { goto fail; } @@ -1148,7 +1149,7 @@ static uint64_t *store_bitmap_data(BlockDriverState *= bs, memset(buf + write_size, 0, s->cluster_size - write_size); } =20 - ret =3D qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size); + ret =3D qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size,= false); if (ret < 0) { error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); goto fail; @@ -1216,7 +1217,7 @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bi= tmap *bm, Error **errp) } =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, tb_offset, - tb_size * sizeof(tb[0])); + tb_size * sizeof(tb[0]), false); if (ret < 0) { error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); goto fail; diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index d9dafa31e5..df02e7b20a 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -205,13 +205,13 @@ static int qcow2_cache_entry_flush(BlockDriverState *= bs, Qcow2Cache *c, int i) =20 if (c =3D=3D s->refcount_block_cache) { ret =3D qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } else if (c =3D=3D s->l2_table_cache) { ret =3D qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } else { ret =3D qcow2_pre_write_overlap_check(bs, 0, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } =20 if (ret < 0) { diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 4889c166e8..fbd967c5a8 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -153,7 +153,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t = min_size, /* the L1 position has not yet been updated, so these clusters must * indeed be completely free */ ret =3D qcow2_pre_write_overlap_check(bs, 0, new_l1_table_offset, - new_l1_size2); + new_l1_size2, false); if (ret < 0) { goto fail; } @@ -238,7 +238,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_i= ndex) } =20 ret =3D qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, - s->l1_table_offset + 8 * l1_start_index, sizeof(buf)); + s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false); if (ret < 0) { return ret; } @@ -487,6 +487,7 @@ static int coroutine_fn do_perform_cow_write(BlockDrive= rState *bs, unsigned offset_in_cluster, QEMUIOVector *qiov) { + BDRVQcow2State *s =3D bs->opaque; int ret; =20 if (qiov->size =3D=3D 0) { @@ -494,13 +495,13 @@ static int coroutine_fn do_perform_cow_write(BlockDri= verState *bs, } =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, qiov->size); + cluster_offset + offset_in_cluster, qiov->size, true); if (ret < 0) { return ret; } =20 BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); - ret =3D bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster, + ret =3D bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_clust= er, qiov->size, qiov, 0); if (ret < 0) { return ret; @@ -604,6 +605,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uin= t64_t offset, } switch (type) { case QCOW2_CLUSTER_COMPRESSED: + if (has_data_file(bs)) { + qcow2_signal_corruption(bs, true, -1, -1, "Compressed cluster " + "entry found in image with external da= ta " + "file (L2 offset: %#" PRIx64 ", L2 ind= ex: " + "%#x)", l2_offset, l2_index); + ret =3D -EIO; + goto fail; + } /* Compressed clusters can only be processed one by one */ c =3D 1; *cluster_offset &=3D L2E_COMPRESSED_OFFSET_SIZE_MASK; @@ -630,6 +639,17 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uin= t64_t offset, ret =3D -EIO; goto fail; } + if (has_data_file(bs) && *cluster_offset !=3D offset - offset_in_c= luster) + { + qcow2_signal_corruption(bs, true, -1, -1, + "External data file host cluster offse= t %#" + PRIx64 " does not match guest cluster " + "offset: %#" PRIx64 + ", L2 index: %#x)", *cluster_offset, + offset - offset_in_cluster, l2_index); + ret =3D -EIO; + goto fail; + } break; default: abort(); @@ -753,6 +773,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDr= iverState *bs, int64_t cluster_offset; int nb_csectors; =20 + if (has_data_file(bs)) { + return 0; + } + ret =3D get_cluster_table(bs, offset, &l2_slice, &l2_index); if (ret < 0) { return 0; @@ -1242,6 +1266,13 @@ static int do_alloc_cluster_offset(BlockDriverState = *bs, uint64_t guest_offset, trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offs= et, *host_offset, *nb_clusters); =20 + if (has_data_file(bs)) { + assert(*host_offset =3D=3D INV_OFFSET || + *host_offset =3D=3D start_of_cluster(s, guest_offset)); + *host_offset =3D start_of_cluster(s, guest_offset); + return 0; + } + /* Allocate new clusters */ trace_qcow2_cluster_alloc_phys(qemu_coroutine_self()); if (*host_offset =3D=3D INV_OFFSET) { @@ -1918,7 +1949,7 @@ static int expand_zero_clusters_in_l1(BlockDriverStat= e *bs, uint64_t *l1_table, } =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, offset, - s->cluster_size); + s->cluster_size, true); if (ret < 0) { if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { qcow2_free_clusters(bs, offset, s->cluster_size, @@ -1927,7 +1958,8 @@ static int expand_zero_clusters_in_l1(BlockDriverStat= e *bs, uint64_t *l1_table, goto fail; } =20 - ret =3D bdrv_pwrite_zeroes(bs->file, offset, s->cluster_si= ze, 0); + ret =3D bdrv_pwrite_zeroes(s->data_file, offset, + s->cluster_size, 0); if (ret < 0) { if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { qcow2_free_clusters(bs, offset, s->cluster_size, @@ -1954,7 +1986,7 @@ static int expand_zero_clusters_in_l1(BlockDriverStat= e *bs, uint64_t *l1_table, if (l2_dirty) { ret =3D qcow2_pre_write_overlap_check( bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, - slice_offset, slice_size2); + slice_offset, slice_size2, false); if (ret < 0) { goto fail; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 05e7974d7e..79045497c3 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1157,6 +1157,11 @@ void qcow2_free_any_clusters(BlockDriverState *bs, u= int64_t l2_entry, { BDRVQcow2State *s =3D bs->opaque; =20 + if (has_data_file(bs)) { + /* TODO Pass through discard request to s->data_file */ + return; + } + switch (qcow2_get_cluster_type(bs, l2_entry)) { case QCOW2_CLUSTER_COMPRESSED: { @@ -1649,7 +1654,7 @@ static int check_refcounts_l2(BlockDriverState *bs, B= drvCheckResult *res, l2_table[i] =3D cpu_to_be64(l2_entry); ret =3D qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2, - l2e_offset, sizeof(uint64_t)); + l2e_offset, sizeof(uint64_t), false); if (ret < 0) { fprintf(stderr, "ERROR: Overlap check failed\n= "); res->check_errors++; @@ -1898,7 +1903,8 @@ static int check_oflag_copied(BlockDriverState *bs, B= drvCheckResult *res, =20 if (l2_dirty) { ret =3D qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2, - l2_offset, s->cluster_size= ); + l2_offset, s->cluster_size, + false); if (ret < 0) { fprintf(stderr, "ERROR: Could not write L2 table; metadata= " "overlap check failed: %s\n", strerror(-ret)); @@ -2366,7 +2372,7 @@ write_refblocks: } =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, refblock_offset, - s->cluster_size); + s->cluster_size, false); if (ret < 0) { fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret)= ); goto fail; @@ -2417,7 +2423,8 @@ write_refblocks: } =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, reftable_offset, - reftable_size * sizeof(uint64_t)); + reftable_size * sizeof(uint64_t), + false); if (ret < 0) { fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret)); goto fail; @@ -2751,10 +2758,15 @@ QEMU_BUILD_BUG_ON(QCOW2_OL_MAX_BITNR !=3D ARRAY_SIZ= E(metadata_ol_names)); * overlaps; or a negative value (-errno) on error. */ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t o= ffset, - int64_t size) + int64_t size, bool data_file) { - int ret =3D qcow2_check_metadata_overlap(bs, ign, offset, size); + int ret; + + if (data_file && has_data_file(bs)) { + return 0; + } =20 + ret =3D qcow2_check_metadata_overlap(bs, ign, offset, size); if (ret < 0) { return ret; } else if (ret > 0) { @@ -2855,7 +2867,8 @@ static int flush_refblock(BlockDriverState *bs, uint6= 4_t **reftable, if (reftable_index < *reftable_size && (*reftable)[reftable_index]) { offset =3D (*reftable)[reftable_index]; =20 - ret =3D qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_si= ze); + ret =3D qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_si= ze, + false); if (ret < 0) { error_setg_errno(errp, -ret, "Overlap check failed"); return ret; @@ -3121,7 +3134,8 @@ int qcow2_change_refcount_order(BlockDriverState *bs,= int refcount_order, =20 /* Write the new reftable */ ret =3D qcow2_pre_write_overlap_check(bs, 0, new_reftable_offset, - new_reftable_size * sizeof(uint64_= t)); + new_reftable_size * sizeof(uint64_= t), + false); if (ret < 0) { error_setg_errno(errp, -ret, "Overlap check failed"); goto done; diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index bb6a5b7516..b0897886c4 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -184,7 +184,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs) =20 /* The snapshot list position has not yet been updated, so these clust= ers * must indeed be completely free */ - ret =3D qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size); + ret =3D qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size, f= alse); if (ret < 0) { goto fail; } @@ -394,7 +394,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSna= pshotInfo *sn_info) } =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset, - s->l1_size * sizeof(uint64_t)); + s->l1_size * sizeof(uint64_t), fal= se); if (ret < 0) { goto fail; } @@ -533,7 +533,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const cha= r *snapshot_id) } =20 ret =3D qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, - s->l1_table_offset, cur_l1_bytes); + s->l1_table_offset, cur_l1_bytes, + false); if (ret < 0) { goto fail; } diff --git a/block/qcow2.c b/block/qcow2.c index 2b81cf839d..ac9934b3ed 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -140,7 +140,7 @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock = *block, size_t headerlen, /* Zero fill remaining space in cluster so it has predictable * content in case of future spec changes */ clusterlen =3D size_to_clusters(s, headerlen) * s->cluster_size; - assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen) =3D=3D 0); + assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) = =3D=3D 0); ret =3D bdrv_pwrite_zeroes(bs->file, ret + headerlen, clusterlen - headerlen, 0); @@ -1951,7 +1951,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverSt= ate *bs, uint64_t offset, */ if (!cluster_data) { cluster_data =3D - qemu_try_blockalign(bs->file->bs, + qemu_try_blockalign(s->data_file->bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); if (cluster_data =3D=3D NULL) { @@ -1967,7 +1967,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverSt= ate *bs, uint64_t offset, =20 BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); qemu_co_mutex_unlock(&s->lock); - ret =3D bdrv_co_preadv(bs->file, + ret =3D bdrv_co_preadv(s->data_file, cluster_offset + offset_in_cluster, cur_bytes, &hd_qiov, 0); qemu_co_mutex_lock(&s->lock); @@ -2126,7 +2126,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverS= tate *bs, uint64_t offset, } =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, cur_bytes); + cluster_offset + offset_in_cluster, cur_bytes, true); if (ret < 0) { goto fail; } @@ -2140,7 +2140,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverS= tate *bs, uint64_t offset, BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); trace_qcow2_writev_data(qemu_coroutine_self(), cluster_offset + offset_in_cluster); - ret =3D bdrv_co_pwritev(bs->file, + ret =3D bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster, cur_bytes, &hd_qiov, 0); qemu_co_mutex_lock(&s->lock); @@ -3366,7 +3366,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs, goto out; =20 case QCOW2_CLUSTER_NORMAL: - child =3D bs->file; + child =3D s->data_file; copy_offset +=3D offset_into_cluster(s, src_offset); if ((copy_offset & 511) !=3D 0) { ret =3D -EIO; @@ -3436,14 +3436,14 @@ qcow2_co_copy_range_to(BlockDriverState *bs, assert((cluster_offset & 511) =3D=3D 0); =20 ret =3D qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, cur_bytes); + cluster_offset + offset_in_cluster, cur_bytes, true); if (ret < 0) { goto fail; } =20 qemu_co_mutex_unlock(&s->lock); ret =3D bdrv_co_copy_range_to(src, src_offset, - bs->file, + s->data_file, cluster_offset + offset_in_cluster, cur_bytes, read_flags, write_flags); qemu_co_mutex_lock(&s->lock); @@ -3598,6 +3598,16 @@ static int coroutine_fn qcow2_co_truncate(BlockDrive= rState *bs, int64_t offset, int64_t old_file_size, new_file_size; uint64_t nb_new_data_clusters, nb_new_l2_tables; =20 + /* With a data file, preallocation means just allocating the metad= ata + * and forwarding the truncate request to the data file */ + if (has_data_file(bs)) { + ret =3D preallocate_co(bs, old_length, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "Preallocation failed"); + goto fail; + } + } + old_file_size =3D bdrv_getlength(bs->file->bs); if (old_file_size < 0) { error_setg_errno(errp, -old_file_size, @@ -3706,6 +3716,13 @@ static int coroutine_fn qcow2_co_truncate(BlockDrive= rState *bs, int64_t offset, =20 bs->total_sectors =3D offset / BDRV_SECTOR_SIZE; =20 + if (has_data_file(bs)) { + ret =3D bdrv_co_truncate(s->data_file, offset, prealloc, errp); + if (ret < 0) { + goto fail; + } + } + /* write updated header.size */ offset =3D cpu_to_be64(offset); ret =3D bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), @@ -3963,7 +3980,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uin= t64_t offset, } cluster_offset &=3D s->cluster_offset_mask; =20 - ret =3D qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len); + ret =3D qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len, = true); qemu_co_mutex_unlock(&s->lock); if (ret < 0) { goto fail; @@ -3975,8 +3992,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uin= t64_t offset, }; qemu_iovec_init_external(&hd_qiov, &iov, 1); =20 - BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); - ret =3D bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0= ); + BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED); + ret =3D bdrv_co_pwritev(s->data_file, cluster_offset, out_len, &hd_qio= v, 0); if (ret < 0) { goto fail; } --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 154895799298780.64834390682245; Thu, 31 Jan 2019 10:06:32 -0800 (PST) Received: from localhost ([127.0.0.1]:58489 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGjK-0005sA-VB for importer@patchew.org; Thu, 31 Jan 2019 13:06:27 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51461) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGZu-0006HT-Hk for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:43 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZm-0005EY-Ip for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:37 -0500 Received: from mx1.redhat.com ([209.132.183.28]:59798) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZW-00058i-I4; Thu, 31 Jan 2019 12:56:19 -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 03D19124D3A; Thu, 31 Jan 2019 17:56:14 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2A6EE5D9D6; Thu, 31 Jan 2019 17:56:08 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:46 +0100 Message-Id: <20190131175549.11691-9-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.39]); Thu, 31 Jan 2019 17:56:14 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 08/11] qcow2: Add basic data-file infrastructure 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This adds a .bdrv_open option to specify the external data file node. Signed-off-by: Kevin Wolf --- qapi/block-core.json | 3 ++- block/qcow2.h | 4 +++- block/qcow2.c | 25 +++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 7f6b4b3ddd..fc46396079 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2928,7 +2928,8 @@ '*l2-cache-entry-size': 'int', '*refcount-cache-size': 'int', '*cache-clean-interval': 'int', - '*encrypt': 'BlockdevQcow2Encryption' } } + '*encrypt': 'BlockdevQcow2Encryption', + '*data-file': 'BlockdevRef' } } =20 ## # @SshHostKeyCheckMode: diff --git a/block/qcow2.h b/block/qcow2.h index c161970882..e2114900b4 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -91,6 +91,7 @@ =20 #define DEFAULT_CLUSTER_SIZE 65536 =20 +#define QCOW2_OPT_DATA_FILE "data-file" #define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" #define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request" #define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot" @@ -205,7 +206,8 @@ enum { QCOW2_INCOMPAT_DATA_FILE =3D 1 << QCOW2_INCOMPAT_DATA_FILE_BITN= R, =20 QCOW2_INCOMPAT_MASK =3D QCOW2_INCOMPAT_DIRTY - | QCOW2_INCOMPAT_CORRUPT, + | QCOW2_INCOMPAT_CORRUPT + | QCOW2_INCOMPAT_DATA_FILE, }; =20 /* Compatible feature bits */ diff --git a/block/qcow2.c b/block/qcow2.c index ac9934b3ed..376232d3f0 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1441,8 +1441,22 @@ static int coroutine_fn qcow2_do_open(BlockDriverSta= te *bs, QDict *options, goto fail; } =20 - /* TODO Open external data file */ - s->data_file =3D bs->file; + /* Open external data file */ + if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { + s->data_file =3D bdrv_open_child(NULL, options, "data-file", bs, + &child_file, false, errp); + if (!s->data_file) { + ret =3D -EINVAL; + goto fail; + } + } else if (qdict_get(options, QCOW2_OPT_DATA_FILE)) { + error_setg(errp, "'data-file' can only be set for images with an " + "external data file"); + ret =3D -EINVAL; + goto fail; + } else { + s->data_file =3D bs->file; + } =20 /* qcow2_read_extension may have set up the crypto context * if the crypt method needs a header region, some methods @@ -1613,6 +1627,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverStat= e *bs, QDict *options, return ret; =20 fail: + if (has_data_file(bs)) { + bdrv_unref_child(bs, s->data_file); + } g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); qcow2_free_snapshots(bs); @@ -2232,6 +2249,10 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->image_backing_file); g_free(s->image_backing_format); =20 + if (has_data_file(bs)) { + bdrv_unref_child(bs, s->data_file); + } + qcow2_refcount_close(bs); qcow2_free_snapshots(bs); } --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548957972448863.7000761055469; Thu, 31 Jan 2019 10:06:12 -0800 (PST) Received: from localhost ([127.0.0.1]:58487 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGiz-0005Zb-A5 for importer@patchew.org; Thu, 31 Jan 2019 13:06:05 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51521) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGa0-0006PG-Ta for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGZz-0005JN-PT for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:48 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53184) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZe-0005AB-5s; Thu, 31 Jan 2019 12:56:28 -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 5A39B4E916; Thu, 31 Jan 2019 17:56:19 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4379D5D985; Thu, 31 Jan 2019 17:56:13 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:47 +0100 Message-Id: <20190131175549.11691-10-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.38]); Thu, 31 Jan 2019 17:56:19 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 09/11] qcow2: Creating images with external data file 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This adds a .bdrv_create option to use an external data file. Signed-off-by: Kevin Wolf --- qapi/block-core.json | 1 + include/block/block_int.h | 1 + block/qcow2.c | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/qapi/block-core.json b/qapi/block-core.json index fc46396079..060df28797 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3980,6 +3980,7 @@ ## { 'struct': 'BlockdevCreateOptionsQcow2', 'data': { 'file': 'BlockdevRef', + '*data-file': 'BlockdevRef', 'size': 'size', '*version': 'BlockdevQcow2Version', '*backing-file': 'str', diff --git a/include/block/block_int.h b/include/block/block_int.h index f605622216..c5b70b3109 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -56,6 +56,7 @@ #define BLOCK_OPT_NOCOW "nocow" #define BLOCK_OPT_OBJECT_SIZE "object_size" #define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" +#define BLOCK_OPT_DATA_FILE "data_file" =20 #define BLOCK_PROBE_BUF_SIZE 512 =20 diff --git a/block/qcow2.c b/block/qcow2.c index 376232d3f0..6cf862e8b9 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2855,6 +2855,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options= , Error **errp) */ BlockBackend *blk =3D NULL; BlockDriverState *bs =3D NULL; + BlockDriverState *data_bs =3D NULL; QCowHeader *header; size_t cluster_size; int version; @@ -2951,6 +2952,20 @@ qcow2_co_create(BlockdevCreateOptions *create_option= s, Error **errp) } refcount_order =3D ctz32(qcow2_opts->refcount_bits); =20 + if (qcow2_opts->data_file) { + if (version < 3) { + error_setg(errp, "External data files are only supported with " + "compatibility level 1.1 and above (use version=3Dv= 3 or " + "greater)"); + ret =3D -EINVAL; + goto out; + } + data_bs =3D bdrv_open_blockdev_ref(qcow2_opts->data_file, errp); + if (bs =3D=3D NULL) { + ret =3D -EIO; + goto out; + } + } =20 /* Create BlockBackend to write to the image */ blk =3D blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); @@ -3002,6 +3017,10 @@ qcow2_co_create(BlockdevCreateOptions *create_option= s, Error **errp) header->compatible_features |=3D cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS); } + if (data_bs) { + header->incompatible_features |=3D + cpu_to_be64(QCOW2_INCOMPAT_DATA_FILE); + } =20 ret =3D blk_pwrite(blk, 0, header, cluster_size, 0); g_free(header); @@ -3032,6 +3051,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options= , Error **errp) options =3D qdict_new(); qdict_put_str(options, "driver", "qcow2"); qdict_put_str(options, "file", bs->node_name); + if (data_bs) { + qdict_put_str(options, "data-file", data_bs->node_name); + } blk =3D blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, &local_err); @@ -3117,6 +3139,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options= , Error **errp) options =3D qdict_new(); qdict_put_str(options, "driver", "qcow2"); qdict_put_str(options, "file", bs->node_name); + if (data_bs) { + qdict_put_str(options, "data-file", data_bs->node_name); + } blk =3D blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, &local_err); @@ -3130,6 +3155,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options= , Error **errp) out: blk_unref(blk); bdrv_unref(bs); + bdrv_unref(data_bs); return ret; } =20 --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548958773051706.520526029565; Thu, 31 Jan 2019 10:19:33 -0800 (PST) Received: from localhost ([127.0.0.1]:58723 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGvx-0000au-LL for importer@patchew.org; Thu, 31 Jan 2019 13:19:29 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51631) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGaI-0006jW-B4 for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:57:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGa4-0005Od-Tq for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:58 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53218) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGZz-0005Am-Nn; Thu, 31 Jan 2019 12:56:47 -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 DF0A8A4050; Thu, 31 Jan 2019 17:56:20 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 96B912A2C1; Thu, 31 Jan 2019 17:56:19 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:48 +0100 Message-Id: <20190131175549.11691-11-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.38]); Thu, 31 Jan 2019 17:56:20 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 10/11] qcow2: Store data file name in the image 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Rather than requiring that the external data file node is passed explicitly when creating the qcow2 node, store the filename in the designated header extension during .bdrv_create and read it from there as a default during .bdrv_open. Signed-off-by: Kevin Wolf --- block/qcow2.h | 1 + block/qcow2.c | 69 +++++++++++++++++++++++++++++++++++++- tests/qemu-iotests/082.out | 27 +++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/block/qcow2.h b/block/qcow2.h index e2114900b4..a1e2600643 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -341,6 +341,7 @@ typedef struct BDRVQcow2State { * override) */ char *image_backing_file; char *image_backing_format; + char *image_data_file; =20 CoQueue compress_wait_queue; int nb_compress_threads; diff --git a/block/qcow2.c b/block/qcow2.c index 6cf862e8b9..4959bf16a4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -398,6 +398,20 @@ static int qcow2_read_extensions(BlockDriverState *bs,= uint64_t start_offset, #endif break; =20 + case QCOW2_EXT_MAGIC_DATA_FILE: + { + s->image_data_file =3D g_malloc0(ext.len + 1); + ret =3D bdrv_pread(bs->file, offset, s->image_data_file, ext.l= en); + if (ret < 0) { + error_setg_errno(errp, -ret, "ERROR: Could not data file n= ame"); + return ret; + } +#ifdef DEBUG_EXT + printf("Qcow2: Got external data file %s\n", s->image_data_fil= e); +#endif + break; + } + default: /* unknown magic - save it in case we need to rewrite the head= er */ /* If you add a new feature, make sure to also update the fast @@ -1444,7 +1458,18 @@ static int coroutine_fn qcow2_do_open(BlockDriverSta= te *bs, QDict *options, /* Open external data file */ if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { s->data_file =3D bdrv_open_child(NULL, options, "data-file", bs, - &child_file, false, errp); + &child_file, false, &local_err); + if (!s->data_file) { + if (s->image_data_file) { + error_free(local_err); + local_err =3D NULL; + s->data_file =3D bdrv_open_child(s->image_data_file, optio= ns, + "data-file", bs, &child_fil= e, + false, errp); + } else { + error_propagate(errp, local_err); + } + } if (!s->data_file) { ret =3D -EINVAL; goto fail; @@ -1627,6 +1652,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverStat= e *bs, QDict *options, return ret; =20 fail: + g_free(s->image_data_file); if (has_data_file(bs)) { bdrv_unref_child(bs, s->data_file); } @@ -2246,6 +2272,7 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); =20 + g_free(s->image_data_file); g_free(s->image_backing_file); g_free(s->image_backing_format); =20 @@ -2422,6 +2449,19 @@ int qcow2_update_header(BlockDriverState *bs) buflen -=3D ret; } =20 + /* External data file header extension */ + if (has_data_file(bs) && s->image_data_file) { + ret =3D header_ext_add(buf, QCOW2_EXT_MAGIC_DATA_FILE, + s->image_data_file, strlen(s->image_data_file= ), + buflen); + if (ret < 0) { + goto fail; + } + + buf +=3D ret; + buflen -=3D ret; + } + /* Full disk encryption header pointer extension */ if (s->crypto_header.offset !=3D 0) { s->crypto_header.offset =3D cpu_to_be64(s->crypto_header.offset); @@ -3166,6 +3206,7 @@ static int coroutine_fn qcow2_co_create_opts(const ch= ar *filename, QemuOpts *opt QDict *qdict; Visitor *v; BlockDriverState *bs =3D NULL; + BlockDriverState *data_bs =3D NULL; Error *local_err =3D NULL; const char *val; int ret; @@ -3229,6 +3270,26 @@ static int coroutine_fn qcow2_co_create_opts(const c= har *filename, QemuOpts *opt goto finish; } =20 + /* Create and open an external data file (protocol layer) */ + val =3D qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE); + if (val) { + ret =3D bdrv_create_file(val, opts, errp); + if (ret < 0) { + goto finish; + } + + data_bs =3D bdrv_open(val, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, + errp); + if (data_bs =3D=3D NULL) { + ret =3D -EIO; + goto finish; + } + + qdict_del(qdict, BLOCK_OPT_DATA_FILE); + qdict_put_str(qdict, "data-file", data_bs->node_name); + } + /* Set 'driver' and 'node' options */ qdict_put_str(qdict, "driver", "qcow2"); qdict_put_str(qdict, "file", bs->node_name); @@ -3263,6 +3324,7 @@ static int coroutine_fn qcow2_co_create_opts(const ch= ar *filename, QemuOpts *opt finish: qobject_unref(qdict); bdrv_unref(bs); + bdrv_unref(data_bs); qapi_free_BlockdevCreateOptions(create_options); return ret; } @@ -4943,6 +5005,11 @@ static QemuOptsList qcow2_create_opts =3D { .type =3D QEMU_OPT_STRING, .help =3D "Image format of the base image" }, + { + .name =3D BLOCK_OPT_DATA_FILE, + .type =3D QEMU_OPT_STRING, + .help =3D "File name of an external data file" + }, { .name =3D BLOCK_OPT_ENCRYPT, .type =3D QEMU_OPT_BOOL, diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 0ce18c075b..7dc59f6075 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -48,6 +48,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -69,6 +70,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -90,6 +92,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -111,6 +114,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -132,6 +136,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -153,6 +158,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -174,6 +180,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -195,6 +202,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -231,6 +239,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -304,6 +313,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -325,6 +335,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -346,6 +357,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -367,6 +379,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -388,6 +401,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -409,6 +423,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -430,6 +445,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -451,6 +467,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -487,6 +504,7 @@ Supported options: backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -568,6 +586,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -590,6 +609,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -612,6 +632,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -634,6 +655,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -656,6 +678,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -678,6 +701,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -700,6 +724,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -722,6 +747,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' @@ -761,6 +787,7 @@ Creation options for 'qcow2': backing_fmt=3D - Image format of the base image cluster_size=3D - qcow2 cluster size compat=3D - Compatibility level (0.10 or 1.1) + data_file=3D - File name of an external data file encrypt.cipher-alg=3D - Name of encryption cipher algorithm encrypt.cipher-mode=3D - Name of encryption cipher mode encrypt.format=3D - Encrypt the image, format choices: 'aes', 'lu= ks' --=20 2.20.1 From nobody Fri May 3 07:51:31 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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 Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548957911179425.2017407491969; Thu, 31 Jan 2019 10:05:11 -0800 (PST) Received: from localhost ([127.0.0.1]:58453 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGhw-0004cd-HI for importer@patchew.org; Thu, 31 Jan 2019 13:05:00 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51646) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gpGaN-0006ls-At for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:57:12 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gpGa2-0005Mj-0W for qemu-devel@nongnu.org; Thu, 31 Jan 2019 12:56:51 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57748) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gpGa0-0005Bh-6F; Thu, 31 Jan 2019 12:56:48 -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 711FF29A75; Thu, 31 Jan 2019 17:56:22 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-135.ams2.redhat.com [10.36.117.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3208B5D9D6; Thu, 31 Jan 2019 17:56:21 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 31 Jan 2019 18:55:49 +0100 Message-Id: <20190131175549.11691-12-kwolf@redhat.com> In-Reply-To: <20190131175549.11691-1-kwolf@redhat.com> References: <20190131175549.11691-1-kwolf@redhat.com> MIME-Version: 1.0 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.28]); Thu, 31 Jan 2019 17:56:22 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 11/11] qcow2: Add data file to ImageInfoSpecificQCow2 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, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Signed-off-by: Kevin Wolf --- qapi/block-core.json | 1 + block/qcow2.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 060df28797..0eb0637b64 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -74,6 +74,7 @@ { 'struct': 'ImageInfoSpecificQCow2', 'data': { 'compat': 'str', + '*data-file': 'str', '*lazy-refcounts': 'bool', '*corrupt': 'bool', 'refcount-bits': 'int', diff --git a/block/qcow2.c b/block/qcow2.c index 4959bf16a4..e3427f9fcd 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1459,7 +1459,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverStat= e *bs, QDict *options, if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { s->data_file =3D bdrv_open_child(NULL, options, "data-file", bs, &child_file, false, &local_err); - if (!s->data_file) { + if (s->data_file) { + s->image_data_file =3D g_strdup(s->data_file->bs->filename); + } else { if (s->image_data_file) { error_free(local_err); local_err =3D NULL; @@ -4533,6 +4535,8 @@ static ImageInfoSpecific *qcow2_get_specific_info(Blo= ckDriverState *bs) QCOW2_INCOMPAT_CORRUPT, .has_corrupt =3D true, .refcount_bits =3D s->refcount_bits, + .has_data_file =3D !!s->image_data_file, + .data_file =3D g_strdup(s->image_data_file), }; } else { /* if this assertion fails, this probably means a new version was --=20 2.20.1