qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/2] qapi: implementation of the block-dirty-bitmap-dump command


From: Patrik Janoušek
Subject: [PATCH 2/2] qapi: implementation of the block-dirty-bitmap-dump command
Date: Sat, 20 Mar 2021 10:32:35 +0100

Currently, dirty bitmaps are for internal use only and there is
no support for accessing their content from third party-apps.
This patch implements new command block-dirty-bitmap-dump, which
returns content of the dirty bitmap encoded in base64. This is
very useful especially in combination with a drive that uses raw
format because third-party apps can easily use it to create
incremental or differential backup.

Signed-off-by: Patrik Janoušek <pj@patrikjanousek.cz>
---
 block/monitor/bitmap-qmp-cmds.c | 61 +++++++++++++++++++++++++++++++
 qapi/block-core.json            | 64 ++++++++++++++++++++++++++++++++-
 2 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c
index 9f11deec64..7f296e9ba7 100644
--- a/block/monitor/bitmap-qmp-cmds.c
+++ b/block/monitor/bitmap-qmp-cmds.c
@@ -146,6 +146,67 @@ out:
     aio_context_release(aio_context);
 }
 
+BlockDirtyBitmapContent *qmp_block_dirty_bitmap_dump(const char *node,
+                                                     const char *name,
+                                                     bool has_clear, bool 
clear,
+                                                     Error **errp)
+{
+    BlockDriverState *bs;
+    BdrvDirtyBitmap *bitmap;
+    BlockDirtyBitmapContent *bdbc;
+    HBitmap *hb;
+    AioContext *aio_context;
+
+    if (!name || name[0] == '\0') {
+        error_setg(errp, "Bitmap name cannot be empty");
+        return NULL;
+    }
+
+    bs = bdrv_lookup_bs(node, node, errp);
+    if (!bs) {
+        return NULL;
+    }
+
+    aio_context = bdrv_get_aio_context(bs);
+    aio_context_acquire(aio_context);
+
+    bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
+    if (!bitmap || !bs) {
+        return NULL;
+    }
+
+    if (has_clear && clear) {
+        /**
+         * Transactions cannot return value, so "clear" functionality must be
+         * implemented here while holding AiO context
+         */
+
+        bdrv_clear_dirty_bitmap(bitmap, &hb);
+
+        uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
+        uint64_t tb_size = hbitmap_serialization_size(hb, 0, bm_size);
+        uint8_t *buf = g_malloc(tb_size);
+
+        hbitmap_serialize_part(hb, buf, 0, bm_size);
+
+        bdbc = g_new0(BlockDirtyBitmapContent, 1);
+        bdbc->content = g_base64_encode((guchar *) buf, tb_size);
+    } else {
+        uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
+        uint64_t tb_size = bdrv_dirty_bitmap_serialization_size(bitmap, 0, 
bm_size);
+        uint8_t *buf = g_malloc(tb_size);
+
+        bdrv_dirty_bitmap_serialize_part(bitmap, buf, 0, bm_size);
+
+        bdbc = g_new0(BlockDirtyBitmapContent, 1);
+        bdbc->content = g_base64_encode((guchar *) buf, tb_size);
+    }
+
+    aio_context_release(aio_context);
+
+    return bdbc;
+}
+
 BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
                                            bool release,
                                            BlockDriverState **bitmap_bs,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 04ad80bc1e..cbe3dac384 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2031,6 +2031,14 @@
 { 'struct': 'BlockDirtyBitmap',
   'data': { 'node': 'str', 'name': 'str' } }
 
+##
+# @BlockDirtyBitmapContent:
+#
+# @content: content of dirty bitmap (encoded in base64)
+##
+{ 'struct': 'BlockDirtyBitmapContent',
+  'data': { 'content': 'str' } }
+
 ##
 # @BlockDirtyBitmapAdd:
 #
@@ -2056,6 +2064,18 @@
   'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
             '*persistent': 'bool', '*disabled': 'bool' } }
 
+##
+# @BlockDirtyBitmapDump:
+#
+# @node: name of device/node which the bitmap is tracking
+#
+# @name: name of the dirty bitmap (must be less than 1024 bytes)
+#
+# @clear: true if bitmap should be cleared after dump
+##
+{ 'struct': 'BlockDirtyBitmapDump',
+  'data': { 'node': 'str', 'name': 'str', '*clear': 'bool' } }
+
 ##
 # @BlockDirtyBitmapMergeSource:
 #
@@ -2086,6 +2106,26 @@
   'data': { 'node': 'str', 'target': 'str',
             'bitmaps': ['BlockDirtyBitmapMergeSource'] } }
 
+##
+# @block-dirty-bitmap-dump:
+#
+# Dump a dirty bitmap with a name on the node.
+#
+# Returns: - nothing on success
+#          - If @node is not a valid block device or node, DeviceNotFound
+#          - If @name is already taken, GenericError with an explanation
+#
+# Example:
+#
+# -> { "execute": "block-dirty-bitmap-dump",
+#      "arguments": { "node": "drive0", "name": "bitmap0" } }
+# <- { "return": { "content": "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFt... (trunc)" } }
+#
+##
+{ 'command': 'block-dirty-bitmap-dump',
+  'data': 'BlockDirtyBitmapDump',
+  'returns': 'BlockDirtyBitmapContent' }
+
 ##
 # @block-dirty-bitmap-add:
 #
@@ -3908,6 +3948,26 @@
             '*x-dirty-bitmap': 'str',
             '*reconnect-delay': 'uint32' } }
 
+##
+# @BlockdevOptionsRawDirtyBitmap:
+#
+# Dirty bitmap options for the raw driver.
+#
+# @name: the name of the dirty bitmap (Since 2.4)
+#
+# @filename: the filename of the dirty bitmap
+#
+# @granularity: granularity of the dirty bitmap in bytes (since 1.4)
+#
+# @persistent: true if the bitmap was stored on disk, is scheduled to be stored
+#              on disk, or both. (since 4.0)
+#
+# @disabled: true if the bitmap should not be loaded (and saved) automatically
+##
+{ 'struct': 'BlockdevOptionsRawDirtyBitmap',
+  'data': {'*name': 'str', 'filename': 'str', 'granularity': 'uint32',
+           'persistent': 'bool', '*disabled': 'bool' } }
+
 ##
 # @BlockdevOptionsRaw:
 #
@@ -3915,12 +3975,14 @@
 #
 # @offset: position where the block device starts
 # @size: the assumed size of the device
+# @dirty-bitmaps: dirty bitmaps of the raw block device
 #
 # Since: 2.9
 ##
 { 'struct': 'BlockdevOptionsRaw',
   'base': 'BlockdevOptionsGenericFormat',
-  'data': { '*offset': 'int', '*size': 'int' } }
+  'data': { '*offset': 'int', '*size': 'int' ,
+            '*dirty-bitmaps': ['BlockdevOptionsRawDirtyBitmap'] } }
 
 ##
 # @BlockdevOptionsThrottle:
-- 
2.31.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]