@@ -38,6 +38,7 @@
#include "qapi/qmp/qstring.h"
#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
+#include "qemu/error-report.h"
BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
BlockDriverState *bs, Error **errp)
@@ -868,6 +869,11 @@ void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
if (info->has_format_specific) {
func_fprintf(f, "Format specific information:\n");
+ if (info->format_specific &&
+ info->format_specific->type == IMAGE_INFO_SPECIFIC_KIND_QCOW2 &&
+ info->format_specific->u.qcow2.data->has_bitmaps == false) {
+ warn_report("Failed to load bitmap list");
+ }
bdrv_image_info_specific_dump(func_fprintf, f, info->format_specific);
}
}
@@ -1006,6 +1006,70 @@ fail:
return false;
}
+static Qcow2BitmapInfoFlagsList *get_bitmap_info_flags(uint32_t flags)
+{
+ Qcow2BitmapInfoFlagsList *list = NULL;
+ Qcow2BitmapInfoFlagsList **plist = &list;
+
+ if (flags & BME_FLAG_IN_USE) {
+ Qcow2BitmapInfoFlagsList *entry = g_new0(Qcow2BitmapInfoFlagsList, 1);
+ entry->value = QCOW2_BITMAP_INFO_FLAGS_IN_USE;
+ *plist = entry;
+ plist = &entry->next;
+ }
+ if (flags & BME_FLAG_AUTO) {
+ Qcow2BitmapInfoFlagsList *entry = g_new0(Qcow2BitmapInfoFlagsList, 1);
+ entry->value = QCOW2_BITMAP_INFO_FLAGS_AUTO;
+ *plist = entry;
+ }
+ return list;
+}
+
+/*
+ * qcow2_get_bitmap_info_list()
+ * Returns a list of QCOW2 bitmap details.
+ * In case of no bitmaps, the function returns NULL and
+ * the @errp parameter is not set (for a 0-length list in the QMP).
+ * When bitmap information can not be obtained, the function returns
+ * NULL and the @errp parameter is set (for omitting the list in QMP).
+ */
+Qcow2BitmapInfoList *qcow2_get_bitmap_info_list(BlockDriverState *bs,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+ Qcow2BitmapInfoList *list = NULL;
+ Qcow2BitmapInfoList **plist = &list;
+
+ if (s->nb_bitmaps == 0) {
+ return NULL;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return NULL;
+ }
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ Qcow2BitmapInfo *info = g_new0(Qcow2BitmapInfo, 1);
+ Qcow2BitmapInfoList *obj = g_new0(Qcow2BitmapInfoList, 1);
+ info->granularity = 1U << bm->granularity_bits;
+ info->name = g_strdup(bm->name);
+ info->flags = get_bitmap_info_flags(bm->flags);
+ info->unknown_flags = bm->flags & BME_RESERVED_FLAGS;
+ info->has_unknown_flags = !!info->unknown_flags;
+ obj->value = info;
+ *plist = obj;
+ plist = &obj->next;
+ }
+
+ bitmap_list_free(bm_list);
+
+ return list;
+}
+
int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated,
Error **errp)
{
@@ -4386,8 +4386,14 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
*spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
.compat = g_strdup("0.10"),
.refcount_bits = s->refcount_bits,
+ .has_bitmaps = true, /* To handle error check properly */
+ .bitmaps = NULL, /* Unsupported for version 2 */
};
} else if (s->qcow_version == 3) {
+ Qcow2BitmapInfoList *bitmaps;
+ Error *local_err = NULL;
+
+ bitmaps = qcow2_get_bitmap_info_list(bs, &local_err);
*spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
.compat = g_strdup("1.1"),
.lazy_refcounts = s->compatible_features &
@@ -4397,7 +4403,14 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
QCOW2_INCOMPAT_CORRUPT,
.has_corrupt = true,
.refcount_bits = s->refcount_bits,
+ .has_bitmaps = !local_err,
+ .bitmaps = bitmaps,
};
+ /*
+ * If an error occurs in obtaining bitmaps, ignore
+ * it to show other QCOW2 specific information.
+ */
+ error_free(local_err);
} else {
/* if this assertion fails, this probably means a new version was
* added without having it covered here */
@@ -684,6 +684,8 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size);
bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+Qcow2BitmapInfoList *qcow2_get_bitmap_info_list(BlockDriverState *bs,
+ Error **errp);
int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated,
Error **errp);
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
@@ -69,6 +69,10 @@
# @encrypt: details about encryption parameters; only set if image
# is encrypted (since 2.10)
#
+# @bitmaps: A list of qcow2 bitmap details (possibly empty, such as for
+# v2 images which do not support bitmaps); absent if bitmap
+# information could not be obtained (since 4.0)
+#
# Since: 1.7
##
{ 'struct': 'ImageInfoSpecificQCow2',
@@ -77,7 +81,8 @@
'*lazy-refcounts': 'bool',
'*corrupt': 'bool',
'refcount-bits': 'int',
- '*encrypt': 'ImageInfoSpecificQCow2Encryption'
+ '*encrypt': 'ImageInfoSpecificQCow2Encryption',
+ '*bitmaps': ['Qcow2BitmapInfo']
} }
##
@@ -454,6 +459,41 @@
'status': 'DirtyBitmapStatus'} }
##
+# @Qcow2BitmapInfoFlags:
+#
+# An enumeration of flags that a bitmap can report to the user.
+#
+# @in-use: The bitmap was not saved correctly and may be inconsistent.
+#
+# @auto: The bitmap must reflect all changes of the virtual disk by any
+# application that would write to this qcow2 file.
+#
+# Since: 4.0
+##
+{ 'enum': 'Qcow2BitmapInfoFlags',
+ 'data': ['in-use', 'auto'] }
+
+##
+# @Qcow2BitmapInfo:
+#
+# Qcow2 bitmap information.
+#
+# @name: the name of the bitmap
+#
+# @granularity: granularity of the bitmap in bytes
+#
+# @flags: flags of the bitmap
+#
+# @unknown-flags: unspecified flags if detected
+#
+# Since: 4.0
+##
+{ 'struct': 'Qcow2BitmapInfo',
+ 'data': {'name': 'str', 'granularity': 'uint32',
+ 'flags': ['Qcow2BitmapInfoFlags'],
+ '*unknown-flags': 'uint32' } }
+
+##
# @BlockLatencyHistogramInfo:
#
# Block latency histogram.
@@ -18,6 +18,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
+ bitmaps:
refcount bits: 16
corrupt: true
can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write
@@ -88,23 +88,23 @@ class TestQMP(TestImageInfoSpecific):
class TestQCow2(TestQemuImgInfo):
'''Testing a qcow2 version 2 image'''
img_options = 'compat=0.10'
- json_compare = { 'compat': '0.10', 'refcount-bits': 16 }
- human_compare = [ 'compat: 0.10', 'refcount bits: 16' ]
+ json_compare = { 'compat': '0.10', 'bitmaps': [], 'refcount-bits': 16 }
+ human_compare = [ 'compat: 0.10', 'bitmaps:', 'refcount bits: 16' ]
class TestQCow3NotLazy(TestQemuImgInfo):
'''Testing a qcow2 version 3 image with lazy refcounts disabled'''
img_options = 'compat=1.1,lazy_refcounts=off'
- json_compare = { 'compat': '1.1', 'lazy-refcounts': False,
+ json_compare = { 'compat': '1.1', 'lazy-refcounts': False, 'bitmaps': [],
'refcount-bits': 16, 'corrupt': False }
- human_compare = [ 'compat: 1.1', 'lazy refcounts: false',
+ human_compare = [ 'compat: 1.1', 'lazy refcounts: false', 'bitmaps:',
'refcount bits: 16', 'corrupt: false' ]
class TestQCow3Lazy(TestQemuImgInfo):
'''Testing a qcow2 version 3 image with lazy refcounts enabled'''
img_options = 'compat=1.1,lazy_refcounts=on'
- json_compare = { 'compat': '1.1', 'lazy-refcounts': True,
+ json_compare = { 'compat': '1.1', 'lazy-refcounts': True, 'bitmaps': [],
'refcount-bits': 16, 'corrupt': False }
- human_compare = [ 'compat: 1.1', 'lazy refcounts: true',
+ human_compare = [ 'compat: 1.1', 'lazy refcounts: true', 'bitmaps:',
'refcount bits: 16', 'corrupt: false' ]
class TestQCow3NotLazyQMP(TestQMP):
@@ -112,7 +112,7 @@ class TestQCow3NotLazyQMP(TestQMP):
with lazy refcounts enabled'''
img_options = 'compat=1.1,lazy_refcounts=off'
qemu_options = 'lazy-refcounts=on'
- compare = { 'compat': '1.1', 'lazy-refcounts': False,
+ compare = { 'compat': '1.1', 'lazy-refcounts': False, 'bitmaps': [],
'refcount-bits': 16, 'corrupt': False }
@@ -121,7 +121,7 @@ class TestQCow3LazyQMP(TestQMP):
with lazy refcounts disabled'''
img_options = 'compat=1.1,lazy_refcounts=on'
qemu_options = 'lazy-refcounts=off'
- compare = { 'compat': '1.1', 'lazy-refcounts': True,
+ compare = { 'compat': '1.1', 'lazy-refcounts': True, 'bitmaps': [],
'refcount-bits': 16, 'corrupt': False }
TestImageInfoSpecific = None
@@ -18,6 +18,7 @@ cluster_size: 4096
Format specific information:
compat: 1.1
lazy refcounts: true
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -30,6 +31,7 @@ cluster_size: 8192
Format specific information:
compat: 1.1
lazy refcounts: true
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -276,6 +278,7 @@ cluster_size: 4096
Format specific information:
compat: 1.1
lazy refcounts: true
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -287,6 +290,7 @@ cluster_size: 8192
Format specific information:
compat: 1.1
lazy refcounts: true
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -529,6 +533,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: true
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -540,6 +545,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -551,6 +557,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: true
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -36,6 +36,7 @@ image: json:{"encrypt.key-secret": "sec0", "driver": "IMGFMT", "file": {"driver"
file format: IMGFMT
virtual size: 16M (16777216 bytes)
Format specific information:
+ bitmaps:
encrypt:
ivgen alg: plain64
hash alg: sha256
@@ -79,6 +80,7 @@ file format: IMGFMT
virtual size: 16M (16777216 bytes)
backing file: TEST_DIR/t.IMGFMT.base
Format specific information:
+ bitmaps:
encrypt:
ivgen alg: plain64
hash alg: sha256
@@ -19,6 +19,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -41,6 +42,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
+ bitmaps:
refcount bits: 16
corrupt: false
@@ -63,6 +65,7 @@ cluster_size: 2097152
Format specific information:
compat: 1.1
lazy refcounts: true
+ bitmaps:
refcount bits: 1
corrupt: false
@@ -86,6 +89,7 @@ backing file: TEST_IMG.base
backing file format: IMGFMT
Format specific information:
compat: 0.10
+ bitmaps:
refcount bits: 16
=== Successful image creation (encrypted) ===
@@ -103,6 +107,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
+ bitmaps:
refcount bits: 16
encrypt:
ivgen alg: plain64
In the 'Format specific information' section of the 'qemu-img info' command output, the supplemental information about existing QCOW2 bitmaps will be shown, such as a bitmap name, flags and granularity: image: /vz/vmprivate/VM1/harddisk.hdd file format: qcow2 virtual size: 64G (68719476736 bytes) disk size: 3.0M cluster_size: 1048576 Format specific information: compat: 1.1 lazy refcounts: true bitmaps: [0]: flags: [0]: in-use [1]: auto name: back-up1 unknown flags: 4 granularity: 65536 [1]: flags: [0]: in-use [1]: auto name: back-up2 unknown flags: 8 granularity: 65536 refcount bits: 16 corrupt: false As the print of the qcow2 specific information expanded by adding the bitmap parameters to the 'qemu-img info' command output, it requires amendment of the output benchmark in the following tests: 060, 065, 082, 198, and 206. Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> --- block/qapi.c | 6 +++++ block/qcow2-bitmap.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 13 ++++++++++ block/qcow2.h | 2 ++ qapi/block-core.json | 42 +++++++++++++++++++++++++++++- tests/qemu-iotests/060.out | 1 + tests/qemu-iotests/065 | 16 ++++++------ tests/qemu-iotests/082.out | 7 +++++ tests/qemu-iotests/198.out | 2 ++ tests/qemu-iotests/206.out | 5 ++++ 10 files changed, 149 insertions(+), 9 deletions(-)