Adds qmp and hmp commands to query/info dirty bitmap. This is needed only for testing.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@parallels.com> --- block.c | 41 ++++++++++++++++++++++++++++ blockdev.c | 24 +++++++++++++++++ hmp-commands.hx | 2 ++ hmp.c | 32 ++++++++++++++++++++++ hmp.h | 1 + include/block/block.h | 2 ++ monitor.c | 7 +++++ qapi/block-core.json | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 5 ++++ 9 files changed, 189 insertions(+) diff --git a/block.c b/block.c index f3a6dd4..e4547d7 100644 --- a/block.c +++ b/block.c @@ -5574,6 +5574,47 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs) return list; } +BlockDirtyBitmapInfo *bdrv_query_dirty_bitmap(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap) +{ + BlockDirtyBitmapInfo *info = g_new0(BlockDirtyBitmapInfo, 1); + BlockDirtyRegionList **plist = &info->dirty_regions; + uint64_t begin = 0, end = 0, size = bitmap->size; + HBitmap *hb = bitmap->bitmap; + + info->dirty_count = bdrv_get_dirty_count(bitmap); + info->granularity = bdrv_dirty_bitmap_granularity(bitmap); + info->size = bitmap->size; + info->name = g_strdup(bitmap->name); + info->disabled = bitmap->disabled; + info->dirty_regions = NULL; + + for (; begin < size; ++begin) { + BlockDirtyRegion *region; + BlockDirtyRegionList *entry; + + if (!hbitmap_get(hb, begin)) { + continue; + } + + for (end = begin + 1; end < size && hbitmap_get(hb, end); ++end) { + ; + } + + region = g_new0(BlockDirtyRegion, 1); + entry = g_new0(BlockDirtyRegionList, 1); + region->start = begin; + region->count = end - begin; + entry->value = region; + *plist = entry; + plist = &entry->next; + + begin = end; + } + + return info; +} + int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector) { if (bitmap) { diff --git a/blockdev.c b/blockdev.c index 13068c7..ad08ea0 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2323,6 +2323,30 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, aio_context_release(aio_context); } +BlockDirtyBitmapInfo *qmp_query_block_dirty_bitmap(const char *node, + const char *name, + Error **errp) +{ + AioContext *aio_context; + BdrvDirtyBitmap *bitmap; + BlockDriverState *bs; + BlockDirtyBitmapInfo *ret = NULL; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap) { + return NULL; + } + + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + + ret = bdrv_query_dirty_bitmap(bs, bitmap); + + aio_context_release(aio_context); + + return ret; +} + int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) { const char *id = qdict_get_str(qdict, "id"); diff --git a/hmp-commands.hx b/hmp-commands.hx index e37bc8b..8c5e580 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1778,6 +1778,8 @@ show roms show the TPM device @item info memory-devices show the memory devices +@item info dirty-bitmap +show dirty bitmap details and content @end table ETEXI diff --git a/hmp.c b/hmp.c index 015499f..2f7ce87 100644 --- a/hmp.c +++ b/hmp.c @@ -788,6 +788,38 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) qapi_free_TPMInfoList(info_list); } +void hmp_info_block_dirty_bitmap(Monitor *mon, const QDict *qdict) +{ + const char *device = qdict_get_str(qdict, "device"); + const char *name = qdict_get_str(qdict, "bitmap"); + BlockDirtyRegionList *region; + + BlockDirtyBitmapInfo *info = + qmp_query_block_dirty_bitmap(device, name, NULL); + + if (!info) { + monitor_printf(mon, "bitmap '%s' for device '%s' doesn't exis\n", + name, device); + return; + } + + monitor_printf(mon, "bitmap '%s'\n", + info->name ? info->name : "no name"); + monitor_printf(mon, "disabled: %s\n", info->disabled ? "true" : "false"); + monitor_printf(mon, "size: %" PRId64 "\n", info->size); + monitor_printf(mon, "granularity: %" PRIu64 "\n", info->granularity); + monitor_printf(mon, "dirty regions begin\n"); + + for (region = info->dirty_regions; region; region = region->next) { + monitor_printf(mon, "%" PRIu64 ": %" PRIu64 "\n", + region->value->start, region->value->count); + } + + monitor_printf(mon, "dirty regions end\n"); + + qapi_free_BlockDirtyBitmapInfo(info); +} + void hmp_quit(Monitor *mon, const QDict *qdict) { monitor_suspend(mon); diff --git a/hmp.h b/hmp.h index 4bb5dca..fdfec15 100644 --- a/hmp.h +++ b/hmp.h @@ -19,6 +19,7 @@ #include "qapi-types.h" #include "qapi/qmp/qdict.h" +void hmp_info_block_dirty_bitmap(Monitor *mon, const QDict *qdict); void hmp_info_name(Monitor *mon, const QDict *qdict); void hmp_info_version(Monitor *mon, const QDict *qdict); void hmp_info_kvm(Monitor *mon, const QDict *qdict); diff --git a/include/block/block.h b/include/block/block.h index f6a50ae..c9d96a6 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -460,6 +460,8 @@ void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap); BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs); uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap); +BlockDirtyBitmapInfo *bdrv_query_dirty_bitmap(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap); bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap); bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap); int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector); diff --git a/monitor.c b/monitor.c index c3cc060..2bcb390 100644 --- a/monitor.c +++ b/monitor.c @@ -2936,6 +2936,13 @@ static mon_cmd_t info_cmds[] = { .mhandler.cmd = hmp_info_memory_devices, }, { + .name = "block-dirty-bitmap", + .args_type = "device:B,bitmap:s", + .params = "device bitmap", + .help = "show dirty bitmap details and content", + .mhandler.cmd = hmp_info_block_dirty_bitmap, + }, + { .name = NULL, }, }; diff --git a/qapi/block-core.json b/qapi/block-core.json index 02bf2b6..25dea80 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -996,6 +996,64 @@ 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } } ## +# @BlockDirtyRegion: +# +# Region in bytes. +# +# @start: first byte +# +# @count: number of bytes in the region +# +# Since: 2.3 +## +{ 'type': 'BlockDirtyRegion', + 'data': { 'start': 'int', 'count': 'int' } } + +## +# @BlockDirtyBitmapInfo +# +# @name: the name of the dirty bitmap +# +# @size: size of the dirty bitmap in sectors +# +# @granularity: granularity of the dirty bitmap in bytes +# +# @disabled: whether the dirty bitmap is disabled +# +# @dirty-count: number of dirty bytes according to the dirty bitmap +# +# @dirty-regions: dirty regions of the bitmap +# +# Since 2.3 +## +{ 'type': 'BlockDirtyBitmapInfo', + 'data': { 'name': 'str', + 'size': 'int', + 'granularity': 'int', + 'disabled': 'bool', + 'dirty-count': 'int', + 'dirty-regions': ['BlockDirtyRegion'] } } + +## +# @DirtyBitmapInfo: +# +# Dirty bitmap information. +# +# @name: #optional the name of the dirty bitmap (Since 2.3) +# +# @count: number of dirty bytes according to the dirty bitmap +# +# @granularity: granularity of the dirty bitmap in bytes (since 1.4) +# +# @enabled: whether the dirty bitmap is enabled (Since 2.3) +# +# Since: 2.3 +## +#{ 'type': 'DirtyBitmapInfo', +# 'data': {'*name': 'str', 'count': 'int', 'granularity': 'int', +# 'enabled': 'bool', 'dirty-regions': ['DirtyRegion']} } + +## # @block-dirty-bitmap-add # # Create a dirty bitmap with a name on the node @@ -1069,6 +1127,23 @@ 'data': 'BlockDirtyBitmap' } ## +# @query-block-dirty-bitmap +# +# Get a description for specified dirty bitmap including it's dirty regions. +# This command is in general for testing purposes. +# +# Returns: @DirtyBitmapInfo +# +# Since: 2.3 +## +{ 'type': 'Mega', +'data': { '*name': 'str' }} + +{ 'command': 'query-block-dirty-bitmap', + 'data': 'BlockDirtyBitmap', + 'returns': 'BlockDirtyBitmapInfo' } + +## # @block_set_io_throttle: # # Change I/O throttle limits for a block drive. diff --git a/qmp-commands.hx b/qmp-commands.hx index 21416fa..b8812a8 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1269,6 +1269,11 @@ EQMP .args_type = "node:B,name:s", .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_clear, }, + { + .name = "query-block-dirty-bitmap", + .args_type = "node:B,name:s", + .mhandler.cmd_new = qmp_marshal_input_query_block_dirty_bitmap, + }, SQMP -- 1.9.1