nbd patches for 2019-02-11

- Add qcow2 bitmap details to 'qemu-img info'
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABCAAGBQJcYd1IAAoJEKeha0olJ0Nq6WMH/1gUi2tc6719yz+pvEwBv7VI
 D720qBoSwEFyrRn1Nk1S3KjKHZ/jemE9bWKsGaIjOf8bIDqlgbElVh/Fc7aBAE6G
 eNGy5zadzhSXDmoNFpqSKjA91OEGPlNm4zMZpqtVQeaGyGzh9PkkPdOkkQZj3M9J
 wf4gmgcFjHbsLgItEx7umn0j0SlDeEyl6WUAKsObEl0Crd+TFoORAimIU6+eoX97
 YZ4+h4s7G+A7cXEPJyfy9c7Et5w9WGRqI0ITBWo7Z9rNLrQt0iT0sgSiZVGgtNbf
 eac9KJiUAkomucC2wUtASJeEKserRdzVpF4FwzA0f4xeDwPZFxtq/+9ncZbWcbs=
 =os/6
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2019-02-11' into staging

nbd patches for 2019-02-11

- Add qcow2 bitmap details to 'qemu-img info'

# gpg: Signature made Mon 11 Feb 2019 20:38:32 GMT
# gpg:                using RSA key A7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full]
# gpg:                 aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full]
# gpg:                 aka "[jpeg image of size 6874]" [full]
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2  F3AA A7A1 6B4A 2527 436A

* remotes/ericb/tags/pull-nbd-2019-02-11:
  qcow2: list of bitmaps new test 242
  qcow2: Add list of bitmaps to ImageInfoSpecificQCow2
  bdrv_query_image_info Error parameter added
  nbd/server: Kill pointless shadowed variable

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-02-12 09:51:50 +00:00
commit d85e60e993
15 changed files with 431 additions and 18 deletions

View file

@ -4462,11 +4462,12 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return drv->bdrv_get_info(bs, bdi);
}
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs)
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs,
Error **errp)
{
BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_get_specific_info) {
return drv->bdrv_get_specific_info(bs);
return drv->bdrv_get_specific_info(bs, errp);
}
return NULL;
}

View file

@ -594,20 +594,17 @@ static int block_crypto_get_info_luks(BlockDriverState *bs,
}
static ImageInfoSpecific *
block_crypto_get_specific_info_luks(BlockDriverState *bs)
block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
{
BlockCrypto *crypto = bs->opaque;
ImageInfoSpecific *spec_info;
QCryptoBlockInfo *info;
info = qcrypto_block_get_info(crypto->block, NULL);
info = qcrypto_block_get_info(crypto->block, errp);
if (!info) {
return NULL;
}
if (info->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) {
qapi_free_QCryptoBlockInfo(info);
return NULL;
}
assert(info->format == Q_CRYPTO_BLOCK_FORMAT_LUKS);
spec_info = g_new(ImageInfoSpecific, 1);
spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS;

View file

@ -282,7 +282,12 @@ void bdrv_query_image_info(BlockDriverState *bs,
info->dirty_flag = bdi.is_dirty;
info->has_dirty_flag = true;
}
info->format_specific = bdrv_get_specific_info(bs);
info->format_specific = bdrv_get_specific_info(bs, &err);
if (err) {
error_propagate(errp, err);
qapi_free_ImageInfo(info);
goto out;
}
info->has_format_specific = info->format_specific != NULL;
backing_filename = bs->backing_file;

View file

@ -1006,6 +1006,82 @@ fail:
return false;
}
static Qcow2BitmapInfoFlagsList *get_bitmap_info_flags(uint32_t flags)
{
Qcow2BitmapInfoFlagsList *list = NULL;
Qcow2BitmapInfoFlagsList **plist = &list;
int i;
static const struct {
int bme; /* Bitmap directory entry flags */
int info; /* The flags to report to the user */
} map[] = {
{ BME_FLAG_IN_USE, QCOW2_BITMAP_INFO_FLAGS_IN_USE },
{ BME_FLAG_AUTO, QCOW2_BITMAP_INFO_FLAGS_AUTO },
};
int map_size = ARRAY_SIZE(map);
for (i = 0; i < map_size; ++i) {
if (flags & map[i].bme) {
Qcow2BitmapInfoFlagsList *entry =
g_new0(Qcow2BitmapInfoFlagsList, 1);
entry->value = map[i].info;
*plist = entry;
plist = &entry->next;
flags &= ~map[i].bme;
}
}
/* Check if the BME_* mapping above is complete */
assert(!flags);
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.
* When bitmap information can not be obtained, the function returns
* NULL and the @errp parameter is set.
*/
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 & ~BME_RESERVED_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)
{

View file

@ -4368,20 +4368,26 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0;
}
static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
Error **errp)
{
BDRVQcow2State *s = bs->opaque;
ImageInfoSpecific *spec_info;
QCryptoBlockInfo *encrypt_info = NULL;
Error *local_err = NULL;
if (s->crypto != NULL) {
encrypt_info = qcrypto_block_get_info(s->crypto, &error_abort);
encrypt_info = qcrypto_block_get_info(s->crypto, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return NULL;
}
}
spec_info = g_new(ImageInfoSpecific, 1);
*spec_info = (ImageInfoSpecific){
.type = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
.u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1),
.u.qcow2.data = g_new0(ImageInfoSpecificQCow2, 1),
};
if (s->qcow_version == 2) {
*spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
@ -4389,6 +4395,13 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
.refcount_bits = s->refcount_bits,
};
} else if (s->qcow_version == 3) {
Qcow2BitmapInfoList *bitmaps;
bitmaps = qcow2_get_bitmap_info_list(bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
qapi_free_ImageInfoSpecific(spec_info);
return NULL;
}
*spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
.compat = g_strdup("1.1"),
.lazy_refcounts = s->compatible_features &
@ -4398,6 +4411,8 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
QCOW2_INCOMPAT_CORRUPT,
.has_corrupt = true,
.refcount_bits = s->refcount_bits,
.has_bitmaps = !!bitmaps,
.bitmaps = bitmaps,
};
} else {
/* if this assertion fails, this probably means a new version was

View file

@ -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);

View file

@ -2543,7 +2543,8 @@ static int coroutine_fn vmdk_co_check(BlockDriverState *bs,
return ret;
}
static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs,
Error **errp)
{
int i;
BDRVVmdkState *s = bs->opaque;

View file

@ -478,7 +478,8 @@ const char *bdrv_get_device_name(const BlockDriverState *bs);
const char *bdrv_get_device_or_node_name(const BlockDriverState *bs);
int bdrv_get_flags(BlockDriverState *bs);
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs);
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs,
Error **errp);
void bdrv_round_to_clusters(BlockDriverState *bs,
int64_t offset, int64_t bytes,
int64_t *cluster_offset,

View file

@ -319,7 +319,8 @@ struct BlockDriver {
const char *name,
Error **errp);
int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs);
ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs,
Error **errp);
int coroutine_fn (*bdrv_save_vmstate)(BlockDriverState *bs,
QEMUIOVector *qiov,

View file

@ -1495,7 +1495,6 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
if (bitmap) {
BdrvDirtyBitmap *bm = NULL;
BlockDriverState *bs = blk_bs(blk);
while (true) {
bm = bdrv_find_dirty_bitmap(bs, bitmap);

View file

@ -69,6 +69,8 @@
# @encrypt: details about encryption parameters; only set if image
# is encrypted (since 2.10)
#
# @bitmaps: A list of qcow2 bitmap details (since 4.0)
#
# Since: 1.7
##
{ 'struct': 'ImageInfoSpecificQCow2',
@ -77,7 +79,8 @@
'*lazy-refcounts': 'bool',
'*corrupt': 'bool',
'refcount-bits': 'int',
'*encrypt': 'ImageInfoSpecificQCow2Encryption'
'*encrypt': 'ImageInfoSpecificQCow2Encryption',
'*bitmaps': ['Qcow2BitmapInfo']
} }
##
@ -453,6 +456,42 @@
'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32',
'status': 'DirtyBitmapStatus'} }
##
# @Qcow2BitmapInfoFlags:
#
# An enumeration of flags that a bitmap can report to the user.
#
# @in-use: This flag is set by any process actively modifying the qcow2 file,
# and cleared when the updated bitmap is flushed to the qcow2 image.
# The presence of this flag in an offline image means that the bitmap
# was not saved correctly after its last usage, and may contain
# inconsistent data.
#
# @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
#
# Since: 4.0
##
{ 'struct': 'Qcow2BitmapInfo',
'data': {'name': 'str', 'granularity': 'uint32',
'flags': ['Qcow2BitmapInfoFlags'] } }
##
# @BlockLatencyHistogramInfo:
#

View file

@ -1661,6 +1661,7 @@ static int info_f(BlockBackend *blk, int argc, char **argv)
BlockDriverState *bs = blk_bs(blk);
BlockDriverInfo bdi;
ImageInfoSpecific *spec_info;
Error *local_err = NULL;
char s1[64], s2[64];
int ret;
@ -1682,7 +1683,11 @@ static int info_f(BlockBackend *blk, int argc, char **argv)
printf("cluster size: %s\n", s1);
printf("vm state offset: %s\n", s2);
spec_info = bdrv_get_specific_info(bs);
spec_info = bdrv_get_specific_info(bs, &local_err);
if (local_err) {
error_report_err(local_err);
return -EIO;
}
if (spec_info) {
printf("Format specific information:\n");
bdrv_image_info_specific_dump(fprintf, stdout, spec_info);

104
tests/qemu-iotests/242 Executable file
View file

@ -0,0 +1,104 @@
#!/usr/bin/env python
#
# Test for qcow2 bitmap printed information
#
# Copyright (c) 2019 Virtuozzo International GmbH
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import iotests
import json
from iotests import qemu_img_create, qemu_io, qemu_img_pipe, \
file_path, img_info_log, log, filter_qemu_io
iotests.verify_image_format(supported_fmts=['qcow2'])
disk = file_path('disk')
chunk = 256 * 1024
bitmap_flag_unknown = 1 << 2
# flag_offset = 5*cluster_size + flag_offset_in_bitmap_directory_entry
flag_offset = 0x5000f
def print_bitmap(extra_args):
log('qemu-img info dump:\n')
img_info_log(disk, extra_args=extra_args)
result = json.loads(qemu_img_pipe('info', '--force-share',
'--output=json', disk))
if 'bitmaps' in result['format-specific']['data']:
bitmaps = result['format-specific']['data']['bitmaps']
log('The same bitmaps in JSON format:')
log(bitmaps, indent=2)
else:
log('No bitmap in JSON format output')
def add_bitmap(bitmap_number, persistent, disabled):
granularity = 1 << (13 + bitmap_number)
bitmap_name = 'bitmap-' + str(bitmap_number-1)
vm = iotests.VM().add_drive(disk)
vm.launch()
vm.qmp_log('block-dirty-bitmap-add', node='drive0', name=bitmap_name,
granularity=granularity, persistent=persistent,
disabled=disabled)
vm.shutdown()
def write_to_disk(offset, size):
write = 'write {} {}'.format(offset, size)
log(qemu_io('-c', write, disk), filters=[filter_qemu_io])
def toggle_flag(offset):
with open(disk, "r+b") as f:
f.seek(offset, 0)
c = f.read(1)
toggled = chr(ord(c) ^ bitmap_flag_unknown)
f.seek(-1, 1)
f.write(toggled)
qemu_img_create('-f', iotests.imgfmt, disk, '1M')
for num in range(1, 4):
disabled = False
if num == 2:
disabled = True
log('Test {}'.format(num))
add_bitmap(num, num > 1, disabled)
write_to_disk((num-1) * chunk, chunk)
print_bitmap([])
log('')
vm = iotests.VM().add_drive(disk)
vm.launch()
num += 1
log('Test {}\nChecking "in-use" flag...'.format(num))
print_bitmap(['--force-share'])
vm.shutdown()
num += 1
log('\nTest {}'.format(num))
qemu_img_create('-f', iotests.imgfmt, disk, '1M')
add_bitmap(1, True, False)
log('Write an unknown bitmap flag \'{}\' into a new QCOW2 image at offset {}'
.format(hex(bitmap_flag_unknown), flag_offset))
toggle_flag(flag_offset)
img_info_log(disk)
toggle_flag(flag_offset)
log('Unset the unknown bitmap flag \'{}\' in the bitmap directory entry:\n'
.format(hex(bitmap_flag_unknown)))
img_info_log(disk)
log('Test complete')

166
tests/qemu-iotests/242.out Normal file
View file

@ -0,0 +1,166 @@
Test 1
{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": false, "granularity": 16384, "name": "bitmap-0", "node": "drive0", "persistent": false}}
{"return": {}}
wrote 262144/262144 bytes at offset 0
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img info dump:
image: TEST_IMG
file format: IMGFMT
virtual size: 1.0M (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
refcount bits: 16
corrupt: false
No bitmap in JSON format output
Test 2
{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": true, "granularity": 32768, "name": "bitmap-1", "node": "drive0", "persistent": true}}
{"return": {}}
wrote 262144/262144 bytes at offset 262144
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img info dump:
image: TEST_IMG
file format: IMGFMT
virtual size: 1.0M (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
bitmaps:
[0]:
flags:
name: bitmap-1
granularity: 32768
refcount bits: 16
corrupt: false
The same bitmaps in JSON format:
[
{
"flags": [],
"granularity": 32768,
"name": "bitmap-1"
}
]
Test 3
{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": false, "granularity": 65536, "name": "bitmap-2", "node": "drive0", "persistent": true}}
{"return": {}}
wrote 262144/262144 bytes at offset 524288
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img info dump:
image: TEST_IMG
file format: IMGFMT
virtual size: 1.0M (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
bitmaps:
[0]:
flags:
name: bitmap-1
granularity: 32768
[1]:
flags:
[0]: auto
name: bitmap-2
granularity: 65536
refcount bits: 16
corrupt: false
The same bitmaps in JSON format:
[
{
"flags": [],
"granularity": 32768,
"name": "bitmap-1"
},
{
"flags": [
"auto"
],
"granularity": 65536,
"name": "bitmap-2"
}
]
Test 4
Checking "in-use" flag...
qemu-img info dump:
image: TEST_IMG
file format: IMGFMT
virtual size: 1.0M (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
bitmaps:
[0]:
flags:
[0]: in-use
name: bitmap-1
granularity: 32768
[1]:
flags:
[0]: in-use
[1]: auto
name: bitmap-2
granularity: 65536
refcount bits: 16
corrupt: false
The same bitmaps in JSON format:
[
{
"flags": [
"in-use"
],
"granularity": 32768,
"name": "bitmap-1"
},
{
"flags": [
"in-use",
"auto"
],
"granularity": 65536,
"name": "bitmap-2"
}
]
Test 5
{"execute": "block-dirty-bitmap-add", "arguments": {"disabled": false, "granularity": 16384, "name": "bitmap-0", "node": "drive0", "persistent": true}}
{"return": {}}
Write an unknown bitmap flag '0x4' into a new QCOW2 image at offset 327695
qemu-img: Could not open 'TEST_IMG': Bitmap 'bitmap-0' doesn't satisfy the constraints
Unset the unknown bitmap flag '0x4' in the bitmap directory entry:
image: TEST_IMG
file format: IMGFMT
virtual size: 1.0M (1048576 bytes)
cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
bitmaps:
[0]:
flags:
[0]: auto
name: bitmap-0
granularity: 16384
refcount bits: 16
corrupt: false
Test complete

View file

@ -238,3 +238,4 @@
238 auto quick
239 rw auto quick
240 auto quick
242 rw auto quick