ddf19c
From af4d66e07c86d7593f7d18ae4b6a2151123b529b Mon Sep 17 00:00:00 2001
ddf19c
From: Eric Blake <eblake@redhat.com>
ddf19c
Date: Tue, 2 Jun 2020 02:34:17 +0100
ddf19c
Subject: [PATCH 12/26] qcow2: Expose bitmaps' size during measure
ddf19c
ddf19c
RH-Author: Eric Blake <eblake@redhat.com>
ddf19c
Message-id: <20200602023420.2133649-10-eblake@redhat.com>
ddf19c
Patchwork-id: 97072
ddf19c
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 09/12] qcow2: Expose bitmaps' size during measure
ddf19c
Bugzilla: 1779893 1779904
ddf19c
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
ddf19c
RH-Acked-by: Max Reitz <mreitz@redhat.com>
ddf19c
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
ddf19c
ddf19c
It's useful to know how much space can be occupied by qcow2 persistent
ddf19c
bitmaps, even though such metadata is unrelated to the guest-visible
ddf19c
data.  Report this value as an additional QMP field, present when
ddf19c
measuring an existing image and output format that both support
ddf19c
bitmaps.  Update iotest 178 and 190 to updated output, as well as new
ddf19c
coverage in 190 demonstrating non-zero values made possible with the
ddf19c
recently-added qemu-img bitmap command (see 3b51ab4b).
ddf19c
ddf19c
The new 'bitmaps size:' field is displayed automatically as part of
ddf19c
'qemu-img measure' any time it is present in QMP (that is, any time
ddf19c
both the source image being measured and destination format support
ddf19c
bitmaps, even if the measurement is 0 because there are no bitmaps
ddf19c
present).  If the field is absent, it means that no bitmaps can be
ddf19c
copied (source, destination, or both lack bitmaps, including when
ddf19c
measuring based on size rather than on a source image).  This behavior
ddf19c
is compatible with an upcoming patch adding 'qemu-img convert
ddf19c
--bitmaps': that command will fail in the same situations where this
ddf19c
patch omits the field.
ddf19c
ddf19c
The addition of a new field demonstrates why we should always
ddf19c
zero-initialize qapi C structs; while the qcow2 driver still fully
ddf19c
populates all fields, the raw and crypto drivers had to be tweaked to
ddf19c
avoid uninitialized data.
ddf19c
ddf19c
Consideration was also given towards having a 'qemu-img measure
ddf19c
--bitmaps' which errors out when bitmaps are not possible, and
ddf19c
otherwise sums the bitmaps into the existing allocation totals rather
ddf19c
than displaying as a separate field, as a potential convenience
ddf19c
factor.  But this was ultimately decided to be more complexity than
ddf19c
necessary when the QMP interface was sufficient enough with bitmaps
ddf19c
remaining a separate field.
ddf19c
ddf19c
See also: https://bugzilla.redhat.com/1779904
ddf19c
ddf19c
Reported-by: Nir Soffer <nsoffer@redhat.com>
ddf19c
Signed-off-by: Eric Blake <eblake@redhat.com>
ddf19c
Message-Id: <20200521192137.1120211-3-eblake@redhat.com>
ddf19c
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
ddf19c
(cherry picked from commit 5d72c68b49769c927e90b78af6d90f6a384b26ac)
ddf19c
ddf19c
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ddf19c
ddf19c
Conflicts:
ddf19c
	block/crypto.c - commit a9da6e49 not present (no measure support)
ddf19c
	docs/tools/qemu-img.rst - changes in qemu-img.texi instead
ddf19c
Signed-off-by: Eric Blake <eblake@redhat.com>
ddf19c
ddf19c
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ddf19c
---
ddf19c
 block/qcow2-bitmap.c             | 36 ++++++++++++++++++++++++++++++
ddf19c
 block/qcow2.c                    | 14 +++++++++---
ddf19c
 block/qcow2.h                    |  2 ++
ddf19c
 block/raw-format.c               |  2 +-
ddf19c
 qapi/block-core.json             | 16 +++++++++-----
ddf19c
 qemu-img.c                       |  3 +++
ddf19c
 qemu-img.texi                    |  7 ++++++
ddf19c
 tests/qemu-iotests/178.out.qcow2 | 16 ++++++++++++++
ddf19c
 tests/qemu-iotests/190           | 47 ++++++++++++++++++++++++++++++++++++++--
ddf19c
 tests/qemu-iotests/190.out       | 27 ++++++++++++++++++++++-
ddf19c
 10 files changed, 158 insertions(+), 12 deletions(-)
ddf19c
ddf19c
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
ddf19c
index cbac905..10d1297 100644
ddf19c
--- a/block/qcow2-bitmap.c
ddf19c
+++ b/block/qcow2-bitmap.c
ddf19c
@@ -1766,3 +1766,39 @@ bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs)
ddf19c
 
ddf19c
     return s->qcow_version >= 3;
ddf19c
 }
ddf19c
+
ddf19c
+/*
ddf19c
+ * Compute the space required for bitmaps in @bs.
ddf19c
+ *
ddf19c
+ * The computation is based as if copying to a new image with the
ddf19c
+ * given @cluster_size, which may differ from the cluster size in @bs.
ddf19c
+ */
ddf19c
+uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
ddf19c
+                                                uint32_t cluster_size)
ddf19c
+{
ddf19c
+    uint64_t bitmaps_size = 0;
ddf19c
+    BdrvDirtyBitmap *bm;
ddf19c
+    size_t bitmap_dir_size = 0;
ddf19c
+
ddf19c
+    FOR_EACH_DIRTY_BITMAP(bs, bm) {
ddf19c
+        if (bdrv_dirty_bitmap_get_persistence(bm)) {
ddf19c
+            const char *name = bdrv_dirty_bitmap_name(bm);
ddf19c
+            uint32_t granularity = bdrv_dirty_bitmap_granularity(bm);
ddf19c
+            uint64_t bmbytes =
ddf19c
+                get_bitmap_bytes_needed(bdrv_dirty_bitmap_size(bm),
ddf19c
+                                        granularity);
ddf19c
+            uint64_t bmclusters = DIV_ROUND_UP(bmbytes, cluster_size);
ddf19c
+
ddf19c
+            /* Assume the entire bitmap is allocated */
ddf19c
+            bitmaps_size += bmclusters * cluster_size;
ddf19c
+            /* Also reserve space for the bitmap table entries */
ddf19c
+            bitmaps_size += ROUND_UP(bmclusters * sizeof(uint64_t),
ddf19c
+                                     cluster_size);
ddf19c
+            /* And space for contribution to bitmap directory size */
ddf19c
+            bitmap_dir_size += calc_dir_entry_size(strlen(name), 0);
ddf19c
+        }
ddf19c
+    }
ddf19c
+    bitmaps_size += ROUND_UP(bitmap_dir_size, cluster_size);
ddf19c
+
ddf19c
+    return bitmaps_size;
ddf19c
+}
ddf19c
diff --git a/block/qcow2.c b/block/qcow2.c
ddf19c
index 36b0f7d..dbd870a 100644
ddf19c
--- a/block/qcow2.c
ddf19c
+++ b/block/qcow2.c
ddf19c
@@ -4751,16 +4751,24 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
ddf19c
         required = virtual_size;
ddf19c
     }
ddf19c
 
ddf19c
-    info = g_new(BlockMeasureInfo, 1);
ddf19c
+    info = g_new0(BlockMeasureInfo, 1);
ddf19c
     info->fully_allocated =
ddf19c
         qcow2_calc_prealloc_size(virtual_size, cluster_size,
ddf19c
                                  ctz32(refcount_bits)) + luks_payload_size;
ddf19c
 
ddf19c
-    /* Remove data clusters that are not required.  This overestimates the
ddf19c
+    /*
ddf19c
+     * Remove data clusters that are not required.  This overestimates the
ddf19c
      * required size because metadata needed for the fully allocated file is
ddf19c
-     * still counted.
ddf19c
+     * still counted.  Show bitmaps only if both source and destination
ddf19c
+     * would support them.
ddf19c
      */
ddf19c
     info->required = info->fully_allocated - virtual_size + required;
ddf19c
+    info->has_bitmaps = version >= 3 && in_bs &&
ddf19c
+        bdrv_supports_persistent_dirty_bitmap(in_bs);
ddf19c
+    if (info->has_bitmaps) {
ddf19c
+        info->bitmaps = qcow2_get_persistent_dirty_bitmap_size(in_bs,
ddf19c
+                                                               cluster_size);
ddf19c
+    }
ddf19c
     return info;
ddf19c
 
ddf19c
 err:
ddf19c
diff --git a/block/qcow2.h b/block/qcow2.h
ddf19c
index ceb1ceb..3297e6b 100644
ddf19c
--- a/block/qcow2.h
ddf19c
+++ b/block/qcow2.h
ddf19c
@@ -768,6 +768,8 @@ int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
ddf19c
                                             const char *name,
ddf19c
                                             Error **errp);
ddf19c
 bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs);
ddf19c
+uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
ddf19c
+                                                uint32_t cluster_size);
ddf19c
 
ddf19c
 ssize_t coroutine_fn
ddf19c
 qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
ddf19c
diff --git a/block/raw-format.c b/block/raw-format.c
ddf19c
index 93b25e1..4bb54f4 100644
ddf19c
--- a/block/raw-format.c
ddf19c
+++ b/block/raw-format.c
ddf19c
@@ -346,7 +346,7 @@ static BlockMeasureInfo *raw_measure(QemuOpts *opts, BlockDriverState *in_bs,
ddf19c
                             BDRV_SECTOR_SIZE);
ddf19c
     }
ddf19c
 
ddf19c
-    info = g_new(BlockMeasureInfo, 1);
ddf19c
+    info = g_new0(BlockMeasureInfo, 1);
ddf19c
     info->required = required;
ddf19c
 
ddf19c
     /* Unallocated sectors count towards the file size in raw images */
ddf19c
diff --git a/qapi/block-core.json b/qapi/block-core.json
ddf19c
index a64ad81..2893209 100644
ddf19c
--- a/qapi/block-core.json
ddf19c
+++ b/qapi/block-core.json
ddf19c
@@ -689,18 +689,24 @@
ddf19c
 # efficiently so file size may be smaller than virtual disk size.
ddf19c
 #
ddf19c
 # The values are upper bounds that are guaranteed to fit the new image file.
ddf19c
-# Subsequent modification, such as internal snapshot or bitmap creation, may
ddf19c
-# require additional space and is not covered here.
ddf19c
+# Subsequent modification, such as internal snapshot or further bitmap
ddf19c
+# creation, may require additional space and is not covered here.
ddf19c
 #
ddf19c
-# @required: Size required for a new image file, in bytes.
ddf19c
+# @required: Size required for a new image file, in bytes, when copying just
ddf19c
+#            allocated guest-visible contents.
ddf19c
 #
ddf19c
 # @fully-allocated: Image file size, in bytes, once data has been written
ddf19c
-#                   to all sectors.
ddf19c
+#                   to all sectors, when copying just guest-visible contents.
ddf19c
+#
ddf19c
+# @bitmaps: Additional size required if all the top-level bitmap metadata
ddf19c
+#           in the source image were to be copied to the destination,
ddf19c
+#           present only when source and destination both support
ddf19c
+#           persistent bitmaps. (since 5.1)
ddf19c
 #
ddf19c
 # Since: 2.10
ddf19c
 ##
ddf19c
 { 'struct': 'BlockMeasureInfo',
ddf19c
-  'data': {'required': 'int', 'fully-allocated': 'int'} }
ddf19c
+  'data': {'required': 'int', 'fully-allocated': 'int', '*bitmaps': 'int'} }
ddf19c
 
ddf19c
 ##
ddf19c
 # @query-block:
ddf19c
diff --git a/qemu-img.c b/qemu-img.c
ddf19c
index 11a4537..b57856e 100644
ddf19c
--- a/qemu-img.c
ddf19c
+++ b/qemu-img.c
ddf19c
@@ -5212,6 +5212,9 @@ static int img_measure(int argc, char **argv)
ddf19c
     if (output_format == OFORMAT_HUMAN) {
ddf19c
         printf("required size: %" PRIu64 "\n", info->required);
ddf19c
         printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated);
ddf19c
+        if (info->has_bitmaps) {
ddf19c
+            printf("bitmaps size: %" PRIu64 "\n", info->bitmaps);
ddf19c
+        }
ddf19c
     } else {
ddf19c
         dump_json_block_measure_info(info);
ddf19c
     }
ddf19c
diff --git a/qemu-img.texi b/qemu-img.texi
ddf19c
index abf2771..3670b96 100644
ddf19c
--- a/qemu-img.texi
ddf19c
+++ b/qemu-img.texi
ddf19c
@@ -576,6 +576,7 @@ The following fields are reported:
ddf19c
 @example
ddf19c
 required size: 524288
ddf19c
 fully allocated size: 1074069504
ddf19c
+bitmaps size: 0
ddf19c
 @end example
ddf19c
 
ddf19c
 The @code{required size} is the file size of the new image.  It may be smaller
ddf19c
@@ -586,6 +587,12 @@ been written to all sectors.  This is the maximum size that the image file can
ddf19c
 occupy with the exception of internal snapshots, dirty bitmaps, vmstate data,
ddf19c
 and other advanced image format features.
ddf19c
 
ddf19c
+The @code{bitmaps size} is the additional size required in order to
ddf19c
+copy bitmaps from a source image in addition to the guest-visible
ddf19c
+data; the line is omitted if either source or destination lacks
ddf19c
+bitmap support, or 0 if bitmaps are supported but there is nothing to
ddf19c
+copy.
ddf19c
+
ddf19c
 @item snapshot [--object @var{objectdef}] [--image-opts] [-U] [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
ddf19c
 
ddf19c
 List, apply, create or delete snapshots in image @var{filename}.
ddf19c
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
ddf19c
index 345eab3..b9ed41b 100644
ddf19c
--- a/tests/qemu-iotests/178.out.qcow2
ddf19c
+++ b/tests/qemu-iotests/178.out.qcow2
ddf19c
@@ -37,6 +37,7 @@ qemu-img: The image size is too large (try using a larger cluster size)
ddf19c
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
ddf19c
 required size: 196608
ddf19c
 fully allocated size: 196608
ddf19c
+bitmaps size: 0
ddf19c
 
ddf19c
 converted image file size in bytes: 196608
ddf19c
 
ddf19c
@@ -45,6 +46,7 @@ converted image file size in bytes: 196608
ddf19c
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
ddf19c
 required size: 393216
ddf19c
 fully allocated size: 1074135040
ddf19c
+bitmaps size: 0
ddf19c
 wrote 512/512 bytes at offset 512
ddf19c
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
ddf19c
 wrote 65536/65536 bytes at offset 65536
ddf19c
@@ -53,6 +55,7 @@ wrote 64512/64512 bytes at offset 134217728
ddf19c
 63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
ddf19c
 required size: 589824
ddf19c
 fully allocated size: 1074135040
ddf19c
+bitmaps size: 0
ddf19c
 
ddf19c
 converted image file size in bytes: 524288
ddf19c
 
ddf19c
@@ -60,6 +63,7 @@ converted image file size in bytes: 524288
ddf19c
 
ddf19c
 required size: 524288
ddf19c
 fully allocated size: 1074135040
ddf19c
+bitmaps size: 0
ddf19c
 
ddf19c
 converted image file size in bytes: 458752
ddf19c
 
ddf19c
@@ -67,16 +71,19 @@ converted image file size in bytes: 458752
ddf19c
 
ddf19c
 required size: 1074135040
ddf19c
 fully allocated size: 1074135040
ddf19c
+bitmaps size: 0
ddf19c
 
ddf19c
 == qcow2 input image and LUKS encryption ==
ddf19c
 
ddf19c
 required size: 2686976
ddf19c
 fully allocated size: 1076232192
ddf19c
+bitmaps size: 0
ddf19c
 
ddf19c
 == qcow2 input image and preallocation (human) ==
ddf19c
 
ddf19c
 required size: 1074135040
ddf19c
 fully allocated size: 1074135040
ddf19c
+bitmaps size: 0
ddf19c
 
ddf19c
 converted image file size in bytes: 1074135040
ddf19c
 
ddf19c
@@ -87,6 +94,7 @@ wrote 8388608/8388608 bytes at offset 0
ddf19c
 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
ddf19c
 required size: 8716288
ddf19c
 fully allocated size: 8716288
ddf19c
+bitmaps size: 0
ddf19c
 
ddf19c
 converted image file size in bytes: 8716288
ddf19c
 
ddf19c
@@ -173,6 +181,7 @@ qemu-img: The image size is too large (try using a larger cluster size)
ddf19c
 
ddf19c
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 196608,
ddf19c
     "fully-allocated": 196608
ddf19c
 }
ddf19c
@@ -183,6 +192,7 @@ converted image file size in bytes: 196608
ddf19c
 
ddf19c
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 393216,
ddf19c
     "fully-allocated": 1074135040
ddf19c
 }
ddf19c
@@ -193,6 +203,7 @@ wrote 65536/65536 bytes at offset 65536
ddf19c
 wrote 64512/64512 bytes at offset 134217728
ddf19c
 63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 589824,
ddf19c
     "fully-allocated": 1074135040
ddf19c
 }
ddf19c
@@ -202,6 +213,7 @@ converted image file size in bytes: 524288
ddf19c
 == qcow2 input image with internal snapshot (json) ==
ddf19c
 
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 524288,
ddf19c
     "fully-allocated": 1074135040
ddf19c
 }
ddf19c
@@ -211,6 +223,7 @@ converted image file size in bytes: 458752
ddf19c
 == qcow2 input image and a backing file (json) ==
ddf19c
 
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 1074135040,
ddf19c
     "fully-allocated": 1074135040
ddf19c
 }
ddf19c
@@ -218,6 +231,7 @@ converted image file size in bytes: 458752
ddf19c
 == qcow2 input image and LUKS encryption ==
ddf19c
 
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 2686976,
ddf19c
     "fully-allocated": 1076232192
ddf19c
 }
ddf19c
@@ -225,6 +239,7 @@ converted image file size in bytes: 458752
ddf19c
 == qcow2 input image and preallocation (json) ==
ddf19c
 
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 1074135040,
ddf19c
     "fully-allocated": 1074135040
ddf19c
 }
ddf19c
@@ -237,6 +252,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608
ddf19c
 wrote 8388608/8388608 bytes at offset 0
ddf19c
 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
ddf19c
 {
ddf19c
+    "bitmaps": 0,
ddf19c
     "required": 8716288,
ddf19c
     "fully-allocated": 8716288
ddf19c
 }
ddf19c
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
ddf19c
index eb766ad..5084ccd 100755
ddf19c
--- a/tests/qemu-iotests/190
ddf19c
+++ b/tests/qemu-iotests/190
ddf19c
@@ -2,7 +2,7 @@
ddf19c
 #
ddf19c
 # qemu-img measure sub-command tests on huge qcow2 files
ddf19c
 #
ddf19c
-# Copyright (C) 2017 Red Hat, Inc.
ddf19c
+# Copyright (C) 2017-2020 Red Hat, Inc.
ddf19c
 #
ddf19c
 # This program is free software; you can redistribute it and/or modify
ddf19c
 # it under the terms of the GNU General Public License as published by
ddf19c
@@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
ddf19c
 _supported_fmt qcow2
ddf19c
 _supported_proto file
ddf19c
 
ddf19c
-echo "== Huge file =="
ddf19c
+echo "== Huge file without bitmaps =="
ddf19c
 echo
ddf19c
 
ddf19c
 IMGOPTS='cluster_size=2M' _make_test_img 2T
ddf19c
@@ -51,6 +51,49 @@ $QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG"
ddf19c
 $QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG"
ddf19c
 $QEMU_IMG measure -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG"
ddf19c
 
ddf19c
+echo
ddf19c
+echo "== Huge file with bitmaps =="
ddf19c
+echo
ddf19c
+
ddf19c
+$QEMU_IMG bitmap --add --granularity 512 -f qcow2 "$TEST_IMG" b1
ddf19c
+$QEMU_IMG bitmap --add -g 2M -f qcow2 "$TEST_IMG" b2
ddf19c
+
ddf19c
+# No bitmap without a source
ddf19c
+$QEMU_IMG measure -O qcow2 --size 10M
ddf19c
+# No bitmap output, since raw does not support it
ddf19c
+$QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG"
ddf19c
+# No bitmap output, since no bitmaps on raw source. Munge required size, as
ddf19c
+# some filesystems store the qcow2 file with less sparseness than others
ddf19c
+$QEMU_IMG measure -O qcow2 -f raw "$TEST_IMG" |
ddf19c
+    sed '/^required size:/ s/[0-9][0-9]*/SIZE/'
ddf19c
+# No bitmap output, since v2 does not support it
ddf19c
+$QEMU_IMG measure -O qcow2 -o compat=0.10 -f qcow2 "$TEST_IMG"
ddf19c
+
ddf19c
+# Compute expected output: bitmap clusters + bitmap tables + bitmaps directory
ddf19c
+echo
ddf19c
+val2T=$((2*1024*1024*1024*1024))
ddf19c
+cluster=$((64*1024))
ddf19c
+b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster ))
ddf19c
+b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster ))
ddf19c
+echo expected bitmap $((b1clusters * cluster +
ddf19c
+                        (b1clusters * 8 + cluster - 1) / cluster * cluster +
ddf19c
+                        b2clusters * cluster +
ddf19c
+                        (b2clusters * 8 + cluster - 1) / cluster * cluster +
ddf19c
+                        cluster))
ddf19c
+$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG"
ddf19c
+
ddf19c
+# Compute expected output: bitmap clusters + bitmap tables + bitmaps directory
ddf19c
+echo
ddf19c
+cluster=$((2*1024*1024))
ddf19c
+b1clusters=$(( (val2T/512/8 + cluster - 1) / cluster ))
ddf19c
+b2clusters=$(( (val2T/2/1024/1024/8 + cluster - 1) / cluster ))
ddf19c
+echo expected bitmap $((b1clusters * cluster +
ddf19c
+                        (b1clusters * 8 + cluster - 1) / cluster * cluster +
ddf19c
+                        b2clusters * cluster +
ddf19c
+                        (b2clusters * 8 + cluster - 1) / cluster * cluster +
ddf19c
+                        cluster))
ddf19c
+$QEMU_IMG measure --output=json -O qcow2 -o cluster_size=2M -f qcow2 "$TEST_IMG"
ddf19c
+
ddf19c
 # success, all done
ddf19c
 echo "*** done"
ddf19c
 rm -f $seq.full
ddf19c
diff --git a/tests/qemu-iotests/190.out b/tests/qemu-iotests/190.out
ddf19c
index d001942..ed9d821 100644
ddf19c
--- a/tests/qemu-iotests/190.out
ddf19c
+++ b/tests/qemu-iotests/190.out
ddf19c
@@ -1,11 +1,36 @@
ddf19c
 QA output created by 190
ddf19c
-== Huge file ==
ddf19c
+== Huge file without bitmaps ==
ddf19c
 
ddf19c
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2199023255552
ddf19c
 required size: 2199023255552
ddf19c
 fully allocated size: 2199023255552
ddf19c
 required size: 335806464
ddf19c
 fully allocated size: 2199359062016
ddf19c
+bitmaps size: 0
ddf19c
 required size: 18874368
ddf19c
 fully allocated size: 2199042129920
ddf19c
+bitmaps size: 0
ddf19c
+
ddf19c
+== Huge file with bitmaps ==
ddf19c
+
ddf19c
+required size: 327680
ddf19c
+fully allocated size: 10813440
ddf19c
+required size: 2199023255552
ddf19c
+fully allocated size: 2199023255552
ddf19c
+required size: SIZE
ddf19c
+fully allocated size: 17170432
ddf19c
+required size: 335806464
ddf19c
+fully allocated size: 2199359062016
ddf19c
+
ddf19c
+expected bitmap 537198592
ddf19c
+required size: 335806464
ddf19c
+fully allocated size: 2199359062016
ddf19c
+bitmaps size: 537198592
ddf19c
+
ddf19c
+expected bitmap 545259520
ddf19c
+{
ddf19c
+    "bitmaps": 545259520,
ddf19c
+    "required": 18874368,
ddf19c
+    "fully-allocated": 2199042129920
ddf19c
+}
ddf19c
 *** done
ddf19c
-- 
ddf19c
1.8.3.1
ddf19c