From nobody Sun Sep 27 23:05:58 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=dupond.be ARC-Seal: i=1; a=rsa-sha256; t=1789481146; cv=none; d=zohomail.com; s=zohoarc; b=O/ulC9y1EZ7AyY2PSSBnduMNX88c1Dmo6aQmoNxlpxJuB2yPSIKZay3CatHxfKzAOVXGByfol1/C4aEIeWx974fA+xN/kIsN35R/kYWh880RRI3EBWOErD5kC4ayzNKY8glg9gBSDQ/A2Ml0JnuNQFq9PmT64xzds0VE8/6rMLI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789481146; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=eqA6zRixsUWQNtOaQ6ZRpJ+k8+YdVsVTAlOJK0RFx68=; b=XHGOE9vbQsF8/v/+ri2sFGbW4+VPi4DzrPCoVbcqdd9dbQ/Z42zlh/2Ptn77PY0iofNJm/d+gCEjd2GPBhljCkEFQA6pulCyXf+02J7M1dv+j3QWgdvBqPcBY3bZ27sezkZsgG7au1JrBaJ2mv9qHHAsdP9NvDaANG64RzpzjYw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1789481146067172.93459853713273; Tue, 15 Sep 2026 07:05:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x6Tmc-0000uw-RN; Tue, 15 Sep 2026 10:05:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6TmZ-0000on-7O; Tue, 15 Sep 2026 10:05:11 -0400 Received: from apollo.dupie.be ([2001:bc8:3f2a:101::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6TmV-0002f3-Sd; Tue, 15 Sep 2026 10:05:10 -0400 Received: from lt-jeanlouis (unknown [IPv6:2a02:a03f:fafb:301:46c3:62e6:fe62:23a1]) by apollo.dupie.be (Postfix) with ESMTPSA id 779F21520F9A; Tue, 15 Sep 2026 16:04:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dupond.be; s=dkim; t=1789481102; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eqA6zRixsUWQNtOaQ6ZRpJ+k8+YdVsVTAlOJK0RFx68=; b=BOe5858j8Ygr0vuHvG9Eu3CDu7EEVeW7Vwc/CBeJ0+e2ezxhUQgX/KYZpShY38j/AmI19U CR6l6bhrNJAGSZqzYXj61QfueEi9hvE9/ETQYbXLj4b7S94ikhnksQ8IPJrL3+TLkAwoOJ dJwrZMCWnIN9/AHEMyCx6JFqO/cuGYLTaKqgsgUwRP8l2dfBsYl9wbND4szhpMoig7q72R E3XScO2l+oXmRKtwUsZBtRzQ7pSahdFfFqmeTTP6rpG6R8hid+59W8nKcOROEh6bIFnzMJ NkJOrG4yCKcdSgmzmvUrJiKwIqhdJtEESWQPDk1HJfNc3R4GrVRxOQzmqA4jiA== From: Jean-Louis Dupond To: qemu-devel@nongnu.org Cc: Kevin Wolf , Pierrick Bouvier , John Snow , Vladimir Sementsov-Ogievskiy , Hanna Reitz , Fiona Ebner , qemu-block@nongnu.org, Jean-Louis Dupond Subject: [PATCH v2 1/3] block: add bdrv_open_backing_chain_until Date: Tue, 15 Sep 2026 16:04:41 +0200 Message-ID: <20260915140444.1223798-2-jean-louis@dupond.be> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260915140444.1223798-1-jean-louis@dupond.be> References: <20260915140444.1223798-1-jean-louis@dupond.be> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2001:bc8:3f2a:101::1; envelope-from=jean-louis@dupond.be; helo=apollo.dupie.be X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @dupond.be) X-ZM-MESSAGEID: 1789481153801158500 Content-Type: text/plain; charset="utf-8" Add a new function called bdrv_open_backing_chain_until. This is used to open a block up until a specified backing chain. Modified bdrv_open_inherit to accept a new arg 'open_backing_recursively' to force to not open the next backing. Adjusting all references to keep the existing behaviour. Signed-off-by: Jean-Louis Dupond --- block.c | 72 +++++++++++++++++++++++++----- block/mirror.c | 2 +- include/block/block-global-state.h | 7 ++- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/block.c b/block.c index f0a6042e61..9763137d8c 100644 --- a/block.c +++ b/block.c @@ -83,6 +83,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers =3D static BlockDriverState *bdrv_open_inherit(const char *filename, const char *reference, QDict *options, int flags, + bool open_backing_recursively, BlockDriverState *parent, const BdrvChildClass *child_cla= ss, BdrvChildRole child_role, @@ -3617,6 +3618,7 @@ out: * TODO Can this be unified with bdrv_open_image()? */ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, + bool open_backing_recursively, const char *bdref_key, Error **errp) { ERRP_GUARD(); @@ -3695,9 +3697,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDic= t *parent_options, qdict_put_str(options, "driver", bs->backing_format); } =20 - backing_hd =3D bdrv_open_inherit(backing_filename, reference, options,= 0, bs, - &child_of_bds, bdrv_backing_role(bs), t= rue, - errp); + backing_hd =3D bdrv_open_inherit(backing_filename, reference, options,= 0, + open_backing_recursively, bs, &child_of= _bds, + bdrv_backing_role(bs), true, errp); if (!backing_hd) { bs->open_flags |=3D BDRV_O_NO_BACKING; error_prepend(errp, "Could not open backing file: "); @@ -3733,6 +3735,54 @@ free_exit: return ret; } =20 +int +bdrv_open_backing_chain_until(BlockDriverState *top_bs, + const char *base_filename, + Error **errp) +{ + BlockDriverState *curr =3D top_bs; + int ret; + + GLOBAL_STATE_CODE(); + + if (!base_filename) { + return 0; + } + + if (bdrv_find_backing_image(top_bs, base_filename)) { + return 0; + } + + while (true) { + QDict *options =3D qdict_clone_shallow(curr->options); + + ret =3D bdrv_open_backing_file(curr, options, false, "backing", er= rp); + qobject_unref(options); + if (ret < 0) { + return ret; + } + + bdrv_graph_rdlock_main_loop(); + if (!curr->backing) { + bdrv_graph_rdunlock_main_loop(); + error_setg(errp, + "Did not find '%s' in the backing chain of '%s'", + base_filename, top_bs->filename); + return -ENOENT; + } + bdrv_graph_rdunlock_main_loop(); + + if (bdrv_find_backing_image(curr, base_filename)) { + return 0; + } + + /* Switch to the next layer */ + bdrv_graph_rdlock_main_loop(); + curr =3D curr->backing->bs; + bdrv_graph_rdunlock_main_loop(); + } +} + static BlockDriverState * bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref= _key, BlockDriverState *parent, const BdrvChildClass *child_c= lass, @@ -3767,7 +3817,7 @@ bdrv_open_child_bs(const char *filename, QDict *optio= ns, const char *bdref_key, goto done; } =20 - bs =3D bdrv_open_inherit(filename, reference, image_options, 0, + bs =3D bdrv_open_inherit(filename, reference, image_options, 0, true, parent, child_class, child_role, parse_filename, errp); if (!bs) { @@ -3897,8 +3947,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef = *ref, Error **errp) =20 } =20 - bs =3D bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, fal= se, - errp); + bs =3D bdrv_open_inherit(NULL, reference, qdict, 0, true, NULL, NULL, = 0, + false, errp); obj =3D NULL; qobject_unref(obj); visit_free(v); @@ -3986,7 +4036,8 @@ out: */ static BlockDriverState * no_coroutine_fn bdrv_open_inherit(const char *filename, const char *reference, QDict *opti= ons, - int flags, BlockDriverState *parent, + int flags, bool open_backing_recursively, + BlockDriverState *parent, const BdrvChildClass *child_class, BdrvChildRole child_r= ole, bool parse_filename, Error **errp) { @@ -4199,8 +4250,9 @@ bdrv_open_inherit(const char *filename, const char *r= eference, QDict *options, } =20 /* If there is a backing file, use it */ - if ((flags & BDRV_O_NO_BACKING) =3D=3D 0) { - ret =3D bdrv_open_backing_file(bs, options, "backing", &local_err); + if ((flags & BDRV_O_NO_BACKING) =3D=3D 0 && open_backing_recursively) { + ret =3D bdrv_open_backing_file(bs, options, open_backing_recursive= ly, + "backing", &local_err); if (ret < 0) { goto close_and_fail; } @@ -4283,7 +4335,7 @@ BlockDriverState *bdrv_open(const char *filename, con= st char *reference, { GLOBAL_STATE_CODE(); =20 - return bdrv_open_inherit(filename, reference, options, flags, NULL, + return bdrv_open_inherit(filename, reference, options, flags, true, NU= LL, NULL, 0, true, errp); } =20 diff --git a/block/mirror.c b/block/mirror.c index 089856f4a8..a4dde5d36d 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -785,7 +785,7 @@ static int mirror_exit_common(Job *job) bdrv_graph_rdlock_main_loop(); assert(!bdrv_backing_chain_next(target_bs)); ret =3D bdrv_open_backing_file(bdrv_skip_filters(target_bs), NULL, - "backing", &local_err); + true, "backing", &local_err); bdrv_graph_rdunlock_main_loop(); if (ret < 0) { error_report_err(local_err); diff --git a/include/block/block-global-state.h b/include/block/block-globa= l-state.h index ed89999f0f..e842bed45a 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -110,7 +110,12 @@ bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverS= tate *backing_hd, Error **errp); =20 int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, - const char *bdref_key, Error **errp); + bool open_backing_recursively, const char *bdre= f_key, + Error **errp); + +int bdrv_open_backing_chain_until(BlockDriverState *top_bs, + const char *base_filename, + Error **errp); =20 BlockDriverState * no_coroutine_fn bdrv_open(const char *filename, const char *reference, QDict *options, --=20 2.55.0 From nobody Sun Sep 27 23:05:58 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=dupond.be ARC-Seal: i=1; a=rsa-sha256; t=1789481146; cv=none; d=zohomail.com; s=zohoarc; b=jUGaJFegN076FAB4ufrhltOe6IgfoEToNFFgALM+nmqW3YDIluAdEALpMDG38sRFDEfQ1fJDdruJtgUQmceUMcR4dwX7KAMUHYg+jERx25UKnOaR1dyyGz9L7q5JnR96i2PdLuJ+1uxkTO65IQ5Lc+J/06R/lIDgT6VYIxwKFxc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789481146; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=HyV0LovrdmQQTgOnUJPVUN5lqDJnTHymsLg64Thdd8A=; b=EHy45LnI0EiNBBGe/Us7KZu3k9dnvUxDvQcOBcX9YENlS911ahDprpM9PxcM5q/YtBjOulXNM5kN1t9zaOOMTtsHmbfoOfFRTd4OQj5fx1lm9CP0MfDxYw7hi2IEbhO1H/+rIThOcDvOOxm/dJPrv4lBtg3KLBBuajFrO8r9hRQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1789481146513486.69817301327794; Tue, 15 Sep 2026 07:05:46 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x6Tmg-0000zj-E1; Tue, 15 Sep 2026 10:05:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6Tmd-0000vi-9u; Tue, 15 Sep 2026 10:05:15 -0400 Received: from apollo.dupie.be ([51.159.20.238]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6TmX-0002lq-EP; Tue, 15 Sep 2026 10:05:14 -0400 Received: from lt-jeanlouis (unknown [IPv6:2a02:a03f:fafb:301:46c3:62e6:fe62:23a1]) by apollo.dupie.be (Postfix) with ESMTPSA id 7EA601520F9B; Tue, 15 Sep 2026 16:05:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dupond.be; s=dkim; t=1789481102; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HyV0LovrdmQQTgOnUJPVUN5lqDJnTHymsLg64Thdd8A=; b=O5eNxxjhZ6F5eYaJqppzkTuncMDfiXddijEv06yF+r47LTfhKsueAA7Niqktve1G7WWEBU iywBH+XXETH/UMmCw+UfRFoOXVEI7EAnMbvAJsfLo0NPJucOtIUoy1c0g9qDBcjKSwH1Ue 1BuXNWwPp2NoncKojYuNI/ej6uaej+4gCsVUTVRk/mVAYKOeVSi3/5i6yv5OBg7YFZtHbz 3S7Tu5t9BvT8MxXSxR7s+43143qNSekFNLvEDSNmpVxVB8IHJWT24AKZNxjO98whAQQpWk t4Yj7ykEK9Hho5sJuhFJOBnwF0jZgimOJCKgar8OEQOwhpfpk0oIZA7ogK3sUQ== From: Jean-Louis Dupond To: qemu-devel@nongnu.org Cc: Kevin Wolf , Pierrick Bouvier , John Snow , Vladimir Sementsov-Ogievskiy , Hanna Reitz , Fiona Ebner , qemu-block@nongnu.org, Jean-Louis Dupond Subject: [PATCH v2 2/3] block: support measure for commit Date: Tue, 15 Sep 2026 16:04:42 +0200 Message-ID: <20260915140444.1223798-3-jean-louis@dupond.be> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260915140444.1223798-1-jean-louis@dupond.be> References: <20260915140444.1223798-1-jean-louis@dupond.be> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=51.159.20.238; envelope-from=jean-louis@dupond.be; helo=apollo.dupie.be X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @dupond.be) X-ZM-MESSAGEID: 1789481153332158500 Content-Type: text/plain; charset="utf-8" Add a new option to qemu-img measure to specify the base node you want to merge the image into. This will open all the images between top and base, and calculate the size required for merging this layer into the base image. Also modify the calculation so it takes into account the discard-no-unref setting of the base image. If discard-no-unref is enabled on the base, discarded blocks in the layers above the base will not free clusters in the base image, but will only mark them ZERO. [1]: https://gitlab.com/qemu-project/qemu/-/issues/2369 Signed-off-by: Jean-Louis Dupond --- block.c | 5 +- block/crypto.c | 1 + block/qcow2.c | 82 ++++++++++++++++++++++++++++---- block/raw-format.c | 2 +- docs/tools/qemu-img.rst | 9 +++- include/block/block-io.h | 3 +- include/block/block_int-common.h | 2 +- qemu-img-cmds.hx | 4 +- qemu-img.c | 45 +++++++++++++++--- tests/qemu-iotests/178.out.qcow2 | 6 +-- tests/qemu-iotests/178.out.raw | 6 +-- 11 files changed, 135 insertions(+), 30 deletions(-) diff --git a/block.c b/block.c index 9763137d8c..acc77777ed 100644 --- a/block.c +++ b/block.c @@ -6091,7 +6091,8 @@ int64_t coroutine_fn bdrv_co_get_allocated_file_size(= BlockDriverState *bs) * If an error occurs the @errp pointer is set. */ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, - BlockDriverState *in_bs, Error **errp) + BlockDriverState *in_bs, + BlockDriverState *base_bs, Error **errp) { IO_CODE(); if (!drv->bdrv_measure) { @@ -6100,7 +6101,7 @@ BlockMeasureInfo *bdrv_measure(BlockDriver *drv, Qemu= Opts *opts, return NULL; } =20 - return drv->bdrv_measure(opts, in_bs, errp); + return drv->bdrv_measure(opts, in_bs, base_bs, errp); } =20 /** diff --git a/block/crypto.c b/block/crypto.c index 36abb7af46..e0236b3382 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -634,6 +634,7 @@ block_crypto_co_getlength(BlockDriverState *bs) =20 static BlockMeasureInfo *block_crypto_measure(QemuOpts *opts, BlockDriverState *in_bs, + BlockDriverState *base_bs, Error **errp) { g_autoptr(QCryptoBlockCreateOptions) create_opts =3D NULL; diff --git a/block/qcow2.c b/block/qcow2.c index 7292dd036c..ee9c815830 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5225,7 +5225,7 @@ static coroutine_fn GRAPH_RDLOCK int qcow2_co_flush_t= o_os(BlockDriverState *bs) } =20 static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *i= n_bs, - Error **errp) + BlockDriverState *base_bs, Error **= errp) { Error *local_err =3D NULL; BlockMeasureInfo *info; @@ -5241,6 +5241,7 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts= , BlockDriverState *in_bs, bool has_backing_file; bool has_luks; bool extended_l2; + bool base_discard_no_unref =3D false; size_t l2e_size; =20 /* Parse image creation options */ @@ -5321,6 +5322,13 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opt= s, BlockDriverState *in_bs, goto err; } =20 + if (base_bs && base_bs->drv && + !strcmp(base_bs->drv->format_name, "qcow2")) { + BDRVQcow2State *base_s =3D base_bs->opaque; + + base_discard_no_unref =3D base_s->discard_no_unref; + } + virtual_size =3D ROUND_UP(ssize, cluster_size); =20 if (has_backing_file) { @@ -5336,8 +5344,10 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opt= s, BlockDriverState *in_bs, =20 for (offset =3D 0; offset < ssize; offset +=3D pnum) { int ret; + int retp =3D 0; + bool count =3D false; =20 - ret =3D bdrv_block_status_above(in_bs, NULL, offset, + ret =3D bdrv_block_status_above(in_bs, base_bs, offset, ssize - offset, &pnum, NULL, NULL); if (ret < 0) { @@ -5346,15 +5356,67 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *op= ts, BlockDriverState *in_bs, goto err; } =20 - if (ret & BDRV_BLOCK_ZERO) { + if (ret & BDRV_BLOCK_ZERO && !base_bs) { /* Skip zero regions (safe with no backing file) */ - } else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)= ) =3D=3D - (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) { - /* Extend pnum to end of cluster for next iteration */ - pnum =3D ROUND_UP(offset + pnum, cluster_size) - offse= t; - - /* Count clusters we've seen */ - required +=3D offset % cluster_size + pnum; + } else { + /* + * If there is a base image in the chain, query its + * allocation status for this region so we can decide + * whether the cluster survives a commit into the base. + */ + if (base_bs) { + int64_t pnum_base =3D 0; + retp =3D bdrv_block_status(base_bs, offset, + ssize - offset, &pnum_base, NU= LL, + NULL); + if (retp < 0) { + error_setg_errno(&local_err, -retp, + "Unable to get block status of the bas= e"); + goto err; + } + /* + * If the base contiguous block is smaller, + * use that pnum, so the next iteration starts with + * the smallest offset. + */ + if (pnum_base > 0 && pnum_base < pnum) { + pnum =3D pnum_base; + } + } + + if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) = =3D=3D + (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) { + /* The overlay has its own data here; it is writte= n. */ + count =3D true; + } else if (base_discard_no_unref) { + /* + * With discard-no-unref enabled on the base, clus= ters + * allocated in the base keep their reference when= the + * overlay is committed (discarded clusters are on= ly + * marked zero), so count any cluster that has a v= alid + * offset in the base. + */ + count =3D (retp & BDRV_BLOCK_OFFSET_VALID) !=3D 0; + } else { + /* + * Without discard-no-unref, committing the overlay + * frees the base clusters that the overlay discar= ds + * (the overlay marks them zero). Every other clus= ter + * that is allocated in the base is retained, so c= ount + * it unless the overlay zeroes it out. + */ + count =3D (retp & BDRV_BLOCK_ALLOCATED) && + !((ret & BDRV_BLOCK_ALLOCATED) && + (ret & BDRV_BLOCK_ZERO)); + } + + if (count) { + /* Extend pnum to end of cluster for next iteratio= n */ + pnum =3D ROUND_UP(offset + pnum, cluster_size) - o= ffset; + + /* Count clusters we've seen */ + required +=3D offset % cluster_size + pnum; + } } } } diff --git a/block/raw-format.c b/block/raw-format.c index a57c2922d5..8efa86c8b0 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -369,7 +369,7 @@ raw_co_getlength(BlockDriverState *bs) } =20 static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_= bs, - Error **errp) + BlockDriverState *base_bs, Error **er= rp) { BlockMeasureInfo *info; int64_t required; diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index b0c798b77a..3d9052c4bb 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -632,7 +632,7 @@ Command description: For more information, consult ``include/block/block.h`` in QEMU's source code. =20 -.. option:: measure [--output=3DOFMT] [-O OUTPUT_FMT] [-o OPTIONS] [--size= N | [--object OBJECTDEF] [--image-opts] [-f FMT] [-l SNAPSHOT_PARAM] FILEN= AME] +.. option:: measure [--output=3DOFMT] [-O OUTPUT_FMT] [-o OPTIONS] [-b BAS= E] [--size N | [--object OBJECTDEF] [--image-opts] [-f FMT] [-l SNAPSHOT_PA= RAM] FILENAME] =20 Calculate the file size required for a new image. This information can be used to size logical volumes or SAN LUNs appropriately for @@ -649,6 +649,13 @@ Command description: =20 A snapshot in an existing image can be specified using *SNAPSHOT_PARAM*. =20 + If *BASE* is given, open the backing chain of *FILENAME* up to and + including the image *BASE*, and calculate the file size that *BASE* + will occupy after *FILENAME* is committed into it (i.e. the size of + the merged image). This is different from the default behaviour, + which calculates the size of a standalone copy of *FILENAME*. + *BASE* has to be part of the backing chain of *FILENAME*. + The following fields are reported: =20 :: diff --git a/include/block/block-io.h b/include/block/block-io.h index d34d846bb2..c0abd646d0 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -92,7 +92,8 @@ int64_t co_wrapper_bdrv_rdlock bdrv_get_allocated_file_size(BlockDriverState *bs); =20 BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, - BlockDriverState *in_bs, Error **errp); + BlockDriverState *in_bs, + BlockDriverState *base_bs, Error **errp); =20 int coroutine_fn GRAPH_RDLOCK bdrv_co_delete_file(BlockDriverState *bs, Error **errp); diff --git a/include/block/block_int-common.h b/include/block/block_int-com= mon.h index 147c08155f..b99b1a7d7d 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -731,7 +731,7 @@ struct BlockDriver { BlockDriverState *bs); =20 BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in= _bs, - Error **errp); + BlockDriverState *base_bs, Error **e= rrp); =20 int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev_compressed)( BlockDriverState *bs, int64_t offset, int64_t bytes, diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 6bc8265cfb..f3f5c63773 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -78,9 +78,9 @@ SRST ERST =20 DEF("measure", img_measure, -"measure [--output=3Dofmt] [-O output_fmt] [-o options] [--size N | [--obj= ect objectdef] [--image-opts] [-f fmt] [-l snapshot_param] filename]") +"measure [--output=3Dofmt] [-O output_fmt] [-o options] [--size N | [--obj= ect objectdef] [--image-opts] [-f fmt] [-l snapshot_param] [-b base] filena= me]") SRST -.. option:: measure [--output=3DOFMT] [-O OUTPUT_FMT] [-o OPTIONS] [--size= N | [--object OBJECTDEF] [--image-opts] [-f FMT] [-l SNAPSHOT_PARAM] FILEN= AME] +.. option:: measure [--output=3DOFMT] [-O OUTPUT_FMT] [-o OPTIONS] [--size= N | [--object OBJECTDEF] [--image-opts] [-f FMT] [-l SNAPSHOT_PARAM] [-b B= ASE] FILENAME] ERST =20 DEF("snapshot", img_snapshot, diff --git a/qemu-img.c b/qemu-img.c index 2f63d31141..0567067ec2 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -5694,6 +5694,7 @@ static int img_measure(const img_cmd_t *ccmd, int arg= c, char **argv) BlockBackend *in_blk =3D NULL; BlockDriver *drv; const char *filename =3D NULL; + const char *base_filename =3D NULL; const char *fmt =3D NULL; const char *out_fmt =3D "raw"; char *options =3D NULL; @@ -5705,6 +5706,7 @@ static int img_measure(const img_cmd_t *ccmd, int arg= c, char **argv) QemuOptsList *create_opts =3D NULL; bool image_opts =3D false; int64_t img_size =3D -1; + BlockDriverState *base_bs =3D NULL; BlockMeasureInfo *info =3D NULL; Error *local_err =3D NULL; int ret =3D 1; @@ -5717,6 +5719,7 @@ static int img_measure(const img_cmd_t *ccmd, int arg= c, char **argv) {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {"source-image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, /* img_c= onvert */ {"snapshot", required_argument, 0, 'l'}, + {"base", required_argument, 0, 'b'}, {"target-format", required_argument, 0, 'O'}, {"target-format-options", required_argument, 0, 'o'}, /* img_conve= rt */ {"options", required_argument, 0, 'o'}, @@ -5727,11 +5730,11 @@ static int img_measure(const img_cmd_t *ccmd, int a= rgc, char **argv) {0, 0, 0, 0} }; =20 - while ((c =3D getopt_long(argc, argv, "hf:l:O:o:Us:", + while ((c =3D getopt_long(argc, argv, "hf:l:b:O:o:Us:", long_options, NULL)) !=3D -1) { switch (c) { case 'h': - cmd_help(ccmd, "[-f FMT|--image-opts] [-l SNAPSHOT]\n" + cmd_help(ccmd, "[-f FMT|--image-opts] [-l SNAPSHOT] [-b BASE]\= n" " [-O TARGET_FMT] [-o TARGET_FMT_OPTS] [--output human|json]\n" " [--object OBJDEF] (--size SIZE | FILE)\n" , @@ -5742,6 +5745,8 @@ static int img_measure(const img_cmd_t *ccmd, int arg= c, char **argv) " instead of a file name (incompatible with --format)\n" " -l, --snapshot SNAPSHOT\n" " use this snapshot in FILE as source\n" +" -b, --base BASE\n" +" open FILE backing chain up to BASE (inclusive)\n" " -O, --target-format TARGET_FMT\n" " desired target/output image format (default: raw)\n" " -o TARGET_FMT_OPTS\n" @@ -5779,6 +5784,9 @@ static int img_measure(const img_cmd_t *ccmd, int arg= c, char **argv) snapshot_name =3D optarg; } break; + case 'b': + base_filename =3D optarg; + break; case 'O': out_fmt =3D optarg; break; @@ -5814,8 +5822,10 @@ static int img_measure(const img_cmd_t *ccmd, int ar= gc, char **argv) filename =3D argv[optind]; } =20 - if (!filename && (image_opts || fmt || snapshot_name || sn_opts)) { - error_report("--image-opts, -f, and -l require a filename argument= ."); + if (!filename && (image_opts || fmt || snapshot_name || sn_opts || + base_filename)) { + error_report("--image-opts, -f, -l, and -b require a filename " + "argument."); goto out; } if (filename && img_size !=3D -1) { @@ -5828,12 +5838,34 @@ static int img_measure(const img_cmd_t *ccmd, int a= rgc, char **argv) } =20 if (filename) { - in_blk =3D img_open(image_opts, filename, fmt, 0, + int src_flags =3D 0; + + /* + * When measuring with --base, avoid opening the full backing chai= n. + * We selectively open only up to the requested base afterwards. + * An explicit image specification (--image-opts or a json: filena= me) + * defines the backing chain itself, so it has to be opened normal= ly. + */ + if (base_filename && !image_opts && + !g_str_has_prefix(filename, "json:")) { + src_flags |=3D BDRV_O_NO_BACKING; + } + + in_blk =3D img_open(image_opts, filename, fmt, src_flags, false, false, force_share); if (!in_blk) { goto out; } =20 + if (base_filename) { + if (bdrv_open_backing_chain_until(blk_bs(in_blk), base_filenam= e, + &local_err) < 0) { + error_report_err(local_err); + goto out; + } + base_bs =3D bdrv_find_backing_image(blk_bs(in_blk), base_filen= ame); + } + if (sn_opts) { bdrv_snapshot_load_tmp(blk_bs(in_blk), qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), @@ -5874,7 +5906,8 @@ static int img_measure(const img_cmd_t *ccmd, int arg= c, char **argv) qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort); } =20 - info =3D bdrv_measure(drv, opts, in_blk ? blk_bs(in_blk) : NULL, &loca= l_err); + info =3D bdrv_measure(drv, opts, in_blk ? blk_bs(in_blk) : NULL, base_= bs, + &local_err); if (local_err) { error_report_err(local_err); goto out; diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.= qcow2 index 61506b519f..0984a74a50 100644 --- a/tests/qemu-iotests/178.out.qcow2 +++ b/tests/qemu-iotests/178.out.qcow2 @@ -6,9 +6,9 @@ qemu-img: Either --size N or one filename must be specified. qemu-img: --size N cannot be used together with a filename. qemu-img: At most one filename argument is allowed. qemu-img: Either --size N or one filename must be specified. -qemu-img: --image-opts, -f, and -l require a filename argument. -qemu-img: --image-opts, -f, and -l require a filename argument. -qemu-img: --image-opts, -f, and -l require a filename argument. +qemu-img: --image-opts, -f, -l, and -b require a filename argument. +qemu-img: --image-opts, -f, -l, and -b require a filename argument. +qemu-img: --image-opts, -f, -l, and -b require a filename argument. qemu-img: Invalid option list: , qemu-img: Invalid parameter 'snapshot.foo' qemu-img: Failed in parsing snapshot param 'snapshot.foo=3Dbar' diff --git a/tests/qemu-iotests/178.out.raw b/tests/qemu-iotests/178.out.raw index 6d994a433a..81249e718b 100644 --- a/tests/qemu-iotests/178.out.raw +++ b/tests/qemu-iotests/178.out.raw @@ -6,9 +6,9 @@ qemu-img: Either --size N or one filename must be specified. qemu-img: --size N cannot be used together with a filename. qemu-img: At most one filename argument is allowed. qemu-img: Either --size N or one filename must be specified. -qemu-img: --image-opts, -f, and -l require a filename argument. -qemu-img: --image-opts, -f, and -l require a filename argument. -qemu-img: --image-opts, -f, and -l require a filename argument. +qemu-img: --image-opts, -f, -l, and -b require a filename argument. +qemu-img: --image-opts, -f, -l, and -b require a filename argument. +qemu-img: --image-opts, -f, -l, and -b require a filename argument. qemu-img: Invalid option list: , qemu-img: Invalid parameter 'snapshot.foo' qemu-img: Failed in parsing snapshot param 'snapshot.foo=3Dbar' --=20 2.55.0 From nobody Sun Sep 27 23:05:58 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=dupond.be ARC-Seal: i=1; a=rsa-sha256; t=1789481166; cv=none; d=zohomail.com; s=zohoarc; b=IV40eJFCdRstzzswxJsYvFUqCMVs3U20n6fKuI0bLdysSOkE1f7QRD3q9eeqx1Enl6Y9ChWLVQUtPnebrehrWC5uArUjs8ZA0v5ujdHjlG3BzDmjXl7OHEKjvgrWV6FUIAR3HlPFrEamiHAqMubR0BZ+GSp+ZwfSvLDHQ29ymKI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789481166; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=bQNqMLUwnbWg+oUR7LJH1TXUnvf9xEQaij+T6Ab4rg8=; b=Iya1Lst5cNTWMwWKjngLhqxbmbP94WcrBVFnYjDeN2vygD+CllmTn2e7hAdHjYj0tSYC5FOpp1pl2gqF/IScqJ4acALgrOPBg54sbGoRMw1V8daiV344adi2Qf9JfXZtC89utwgu3jVAh0HhhcvGq/b9HG7ZBKYRgNNkLPyEO7M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1789481166513770.5086796653031; Tue, 15 Sep 2026 07:06:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x6Tmd-0000vD-6F; Tue, 15 Sep 2026 10:05:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6Tmb-0000tY-Aa; Tue, 15 Sep 2026 10:05:13 -0400 Received: from apollo.dupie.be ([51.159.20.238]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x6TmX-0002nb-Bk; Tue, 15 Sep 2026 10:05:12 -0400 Received: from lt-jeanlouis (unknown [IPv6:2a02:a03f:fafb:301:46c3:62e6:fe62:23a1]) by apollo.dupie.be (Postfix) with ESMTPSA id 70D251520F9F; Tue, 15 Sep 2026 16:05:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dupond.be; s=dkim; t=1789481103; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bQNqMLUwnbWg+oUR7LJH1TXUnvf9xEQaij+T6Ab4rg8=; b=FThSvFoXthcJ9EHbYO76qKDwd+Y8yy5+Ag/tNmN9l4wmY0GARrduo/F4s0xCc1g+lSAqxZ EO2BXKWoAFFpl/hIc4Wv6YgPXraZH285NMNWBBrzNxozKz1x7fWyCHD1BX/83I/Ev1mD5F TbbNHqEzG712I9w/dxn63NDl7Unxj22ll4h9GTcjtZbt/kDZ69e/twDh1FsmrFam9dAIJE W+lsMgpOhd3ojSyz9Mob0bEEMt4lvqfeC+WzNRO5j4iDnjJmn07UbtnOPl4d6hvV/v7hfj Md6mrOpwnMS87/7O9vVIfV5ivUMdrqizSd/vtxRKlRhz+F/Ejy9Q+LZ+9t740Q== From: Jean-Louis Dupond To: qemu-devel@nongnu.org Cc: Kevin Wolf , Pierrick Bouvier , John Snow , Vladimir Sementsov-Ogievskiy , Hanna Reitz , Fiona Ebner , qemu-block@nongnu.org, Jean-Louis Dupond Subject: [PATCH v2 3/3] iotests/290: add test case for qemu-img measure Date: Tue, 15 Sep 2026 16:04:43 +0200 Message-ID: <20260915140444.1223798-4-jean-louis@dupond.be> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260915140444.1223798-1-jean-louis@dupond.be> References: <20260915140444.1223798-1-jean-louis@dupond.be> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=51.159.20.238; envelope-from=jean-louis@dupond.be; helo=apollo.dupie.be X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @dupond.be) X-ZM-MESSAGEID: 1789481170119158500 Content-Type: text/plain; charset="utf-8" We create an image, write and discard some data in it, and then create a snapshot. In the snapshot we write and discard again some data. Then we measure the images with the base specified to calculate the merged image size. Finally we commit the image and check it's size. This scenario is executed for discard-no-unref enabled and disabled. Signed-off-by: Jean-Louis Dupond --- tests/qemu-iotests/290 | 45 ++++++++++++++++++++++++++++ tests/qemu-iotests/290.out | 61 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/tests/qemu-iotests/290 b/tests/qemu-iotests/290 index 776b59de1b..2bf811384e 100755 --- a/tests/qemu-iotests/290 +++ b/tests/qemu-iotests/290 @@ -92,6 +92,51 @@ for qcow2_compat in 0.10 1.1; do $QEMU_IMG map "$TEST_IMG" | _filter_testdir done =20 +echo +echo "### Test qemu-img measure for commit differences with 'discard-no-un= ref' option enabled" +echo + +for DISCARD_NO_UNREF in true false; do + echo "# Create a base image and fill it with data" + TEST_IMG=3D"$TEST_IMG.base" _make_test_img 128M + + $QEMU_IO -c 'write 0 8M' "$TEST_IMG.base" | _filter_qemu_io + $QEMU_IO -c 'write 10M 8M' "$TEST_IMG.base" | _filter_qemu_io + $QEMU_IO -c 'write 24M 32M' "$TEST_IMG.base" | _filter_qemu_io + $QEMU_IO -c 'write 56M 20M' "$TEST_IMG.base" | _filter_qemu_io + $QEMU_IO -c "reopen -o discard=3Dunmap,discard-no-unref=3D$DISCARD_NO_= UNREF" \ + -c 'discard 32M 10M' "$TEST_IMG.base" | _filter_qemu_io + + echo "# Create a top image and do some writes and discards" + TEST_IMG=3D"$TEST_IMG.top" _make_test_img -b "$TEST_IMG.base" -F $IMGF= MT 128M + + $QEMU_IO -c "reopen -o discard=3Dunmap,discard-no-unref=3D$DISCARD_NO_= UNREF" -c 'write 16M 8M' \ + -c 'discard 60M 20M' -c 'write 84M 10M' "$TEST_IMG.top" | _filter_= qemu_io + + FILE_JSON=3D"json:{ + 'file': { + 'driver': 'file', + 'filename': '$TEST_IMG.top' + }, + 'driver': 'qcow2', + 'discard': 'unmap', + 'discard-no-unref': '$DISCARD_NO_UNREF', + 'backing': { + 'driver': 'qcow2', + 'discard-no-unref': '$DISCARD_NO_UNREF', + 'file': { + 'driver': 'file', + 'filename': '$TEST_IMG.base' + }, + 'backing': null + }}" + echo "# Measure size with discard-no-unref=3D$DISCARD_NO_UNREF" + $QEMU_IMG measure --output=3Djson -O qcow2 -b "$TEST_IMG.base" "${FILE= _JSON}" + echo "# Merging the top image into the base image" + $QEMU_IMG commit -t none -f qcow2 "${FILE_JSON}" + stat -c"base disk image file size in bytes: %s" "$TEST_IMG.base" +done + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/290.out b/tests/qemu-iotests/290.out index 22b476594f..6dafbfc2b9 100644 --- a/tests/qemu-iotests/290.out +++ b/tests/qemu-iotests/290.out @@ -58,4 +58,65 @@ read 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Output of qemu-img map Offset Length Mapped to File + +### Test qemu-img measure for commit differences with 'discard-no-unref' o= ption enabled + +# Create a base image and fill it with data +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=3DIMGFMT size=3D134217728 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 8388608/8388608 bytes at offset 10485760 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 33554432/33554432 bytes at offset 25165824 +32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 20971520/20971520 bytes at offset 58720256 +20 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 10485760/10485760 bytes at offset 33554432 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Create a top image and do some writes and discards +Formatting 'TEST_DIR/t.IMGFMT.top', fmt=3DIMGFMT size=3D134217728 backing_= file=3DTEST_DIR/t.IMGFMT.base backing_fmt=3DIMGFMT +wrote 8388608/8388608 bytes at offset 16777216 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 20971520/20971520 bytes at offset 62914560 +20 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 10485760/10485760 bytes at offset 88080384 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Measure size with discard-no-unref=3Dtrue +{ + "bitmaps": 0, + "required": 88408064, + "fully-allocated": 134545408 +} +# Merging the top image into the base image +Image committed. +base disk image file size in bytes: 88408064 +# Create a base image and fill it with data +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=3DIMGFMT size=3D134217728 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 8388608/8388608 bytes at offset 10485760 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 33554432/33554432 bytes at offset 25165824 +32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 20971520/20971520 bytes at offset 58720256 +20 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 10485760/10485760 bytes at offset 33554432 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Create a top image and do some writes and discards +Formatting 'TEST_DIR/t.IMGFMT.top', fmt=3DIMGFMT size=3D134217728 backing_= file=3DTEST_DIR/t.IMGFMT.base backing_fmt=3DIMGFMT +wrote 8388608/8388608 bytes at offset 16777216 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 20971520/20971520 bytes at offset 62914560 +20 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 10485760/10485760 bytes at offset 88080384 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Measure size with discard-no-unref=3Dfalse +{ + "bitmaps": 0, + "required": 71630848, + "fully-allocated": 134545408 +} +# Merging the top image into the base image +Image committed. +base disk image file size in bytes: 71630848 *** done --=20 2.55.0