@@ -2006,6 +2006,32 @@
'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
'*persistent': 'bool', '*disabled': 'bool' } }
+##
+# @AllocationMapMode:
+#
+# An enumeration of possible allocation maps that could be merged into target
+# bitmap.
+#
+# @top: The allocation status of the top layer of the attached storage node.
+#
+# Since: 6.1
+##
+{ 'enum': 'AllocationMapMode',
+ 'data': ['top'] }
+
+##
+# @BlockDirtyBitmapMergeExternalSource:
+#
+# @node: name of device/node which the bitmap is tracking
+#
+# @name: name of the dirty bitmap
+#
+# Since: 6.1
+##
+{ 'struct': 'BlockDirtyBitmapMergeExternalSource',
+ 'data': { 'node': 'str', '*name': 'str',
+ '*allocation-map': 'AllocationMapMode' } }
+
##
# @BlockDirtyBitmapMergeSource:
#
@@ -2017,7 +2043,7 @@
##
{ 'alternate': 'BlockDirtyBitmapMergeSource',
'data': { 'local': 'str',
- 'external': 'BlockDirtyBitmap' } }
+ 'external': 'BlockDirtyBitmapMergeExternalSource' } }
##
# @BlockDirtyBitmapMerge:
@@ -2176,7 +2202,8 @@
#
##
{ 'command': 'block-dirty-bitmap-merge',
- 'data': 'BlockDirtyBitmapMerge' }
+ 'data': 'BlockDirtyBitmapMerge',
+ 'coroutine': true }
##
# @BlockDirtyBitmapSha256:
@@ -1361,6 +1361,10 @@ bool bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
const BdrvDirtyBitmap *src,
HBitmap **backup, bool lock);
+int bdrv_merge_allocation_top_to_dirty_bitmap(BdrvDirtyBitmap *dest,
+ BlockDriverState *bs,
+ Error **errp);
+
void bdrv_inc_in_flight(BlockDriverState *bs);
void bdrv_dec_in_flight(BlockDriverState *bs);
@@ -914,6 +914,48 @@ out:
}
}
+int bdrv_merge_allocation_top_to_dirty_bitmap(BdrvDirtyBitmap *dest,
+ BlockDriverState *bs,
+ Error **errp)
+{
+ int ret;
+ int64_t offset = 0;
+ int64_t bytes = bdrv_getlength(bs);
+
+ if (bytes < 0) {
+ error_setg(errp, "Failed to get length of node '%s'",
+ bdrv_get_node_name(bs));
+ return bytes;
+ }
+
+ if (bdrv_dirty_bitmap_size(dest) < bytes) {
+ error_setg(errp, "Bitmap is smaller than node '%s'",
+ bdrv_get_node_name(bs));
+ return -EINVAL;
+ }
+
+ while (bytes) {
+ int64_t cur_bytes = bytes;
+
+ ret = bdrv_is_allocated(bs, offset, cur_bytes, &cur_bytes);
+ if (ret < 0) {
+ error_setg(errp,
+ "Failed to get block allocation status of node '%s'",
+ bdrv_get_node_name(bs));
+ return ret;
+ }
+
+ if (ret) {
+ bdrv_set_dirty_bitmap(dest, offset, cur_bytes);
+ }
+
+ bytes -= cur_bytes;
+ offset += cur_bytes;
+ }
+
+ return 0;
+}
+
/**
* bdrv_dirty_bitmap_merge_internal: merge src into dest.
* Does NOT check bitmap permissions; not suitable for use as public API.
@@ -34,6 +34,7 @@
#include "block/block_int.h"
#include "qapi/qapi-commands-block.h"
+#include "qapi/qapi-types-block-core.h"
#include "qapi/error.h"
/**
@@ -273,8 +274,11 @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
}
for (lst = bms; lst; lst = lst->next) {
+ src = NULL;
+
switch (lst->value->type) {
const char *name, *node;
+ bool has_alloc, has_name;
case QTYPE_QSTRING:
name = lst->value->u.local;
src = bdrv_find_dirty_bitmap(bs, name);
@@ -286,22 +290,57 @@ BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
break;
case QTYPE_QDICT:
node = lst->value->u.external.node;
- name = lst->value->u.external.name;
- src = block_dirty_bitmap_lookup(node, name, NULL, errp);
- if (!src) {
+ has_name = lst->value->u.external.has_name;
+ has_alloc = lst->value->u.external.has_allocation_map;
+ if (has_name == has_alloc) {
+ error_setg(errp, "Exactly one of @name and @allocation-map "
+ "fields must be specified.");
dst = NULL;
goto out;
}
+ if (has_name) {
+ name = lst->value->u.external.name;
+ src = block_dirty_bitmap_lookup(node, name, NULL, errp);
+ if (!src) {
+ dst = NULL;
+ goto out;
+ }
+ } else {
+ int ret;
+ AioContext *old_ctx;
+ assert(has_alloc);
+ /* The only existing mode currently is 'top' */
+ assert(lst->value->u.external.allocation_map ==
+ ALLOCATION_MAP_MODE_TOP);
+
+ bs = bdrv_lookup_bs(node, node, NULL);
+ if (!bs) {
+ error_setg(errp, "Node '%s' not found", node);
+ dst = NULL;
+ goto out;
+ }
+
+ old_ctx = bdrv_co_enter(bs);
+ ret = bdrv_merge_allocation_top_to_dirty_bitmap(anon, bs, errp);
+ bdrv_co_leave(bs, old_ctx);
+
+ if (ret < 0) {
+ dst = NULL;
+ goto out;
+ }
+ }
break;
default:
abort();
}
- bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- dst = NULL;
- goto out;
+ if (src) {
+ bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ dst = NULL;
+ goto out;
+ }
}
}
Add possibility to merge allocation map of specified node into target bitmap. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> --- qapi/block-core.json | 31 +++++++++++++++++-- include/block/block_int.h | 4 +++ block/dirty-bitmap.c | 42 +++++++++++++++++++++++++ block/monitor/bitmap-qmp-cmds.c | 55 ++++++++++++++++++++++++++++----- 4 files changed, 122 insertions(+), 10 deletions(-)