diff --git a/blockdev.c b/blockdev.c
index fa34cf6..f03a415 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2733,6 +2733,57 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
     aio_context_release(aio_context);
 }
 
+void qmp_block_dirty_bitmap_create_successor(const char *node,
+                                             const char *name, Error **errp)
+{
+    AioContext *aio_context;
+    BdrvDirtyBitmap *bitmap;
+    BlockDriverState *bs;
+
+    bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
+    if (!bitmap || !bs) {
+        return;
+    }
+
+    bdrv_dirty_bitmap_create_successor(bs, bitmap, errp);
+
+    aio_context_release(aio_context);
+}
+
+void qmp_block_dirty_bitmap_abdicate(const char *node, const char *name,
+                                     Error **errp)
+{
+    AioContext *aio_context;
+    BdrvDirtyBitmap *bitmap;
+    BlockDriverState *bs;
+
+    bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
+    if (!bitmap || !bs) {
+        return;
+    }
+
+    bdrv_dirty_bitmap_abdicate(bs, bitmap, errp);
+
+    aio_context_release(aio_context);
+}
+
+void qmp_block_dirty_bitmap_reclaim(const char *node, const char *name,
+                                     Error **errp)
+{
+    AioContext *aio_context;
+    BdrvDirtyBitmap *bitmap;
+    BlockDriverState *bs;
+
+    bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
+    if (!bitmap || !bs) {
+        return;
+    }
+
+    bdrv_reclaim_dirty_bitmap(bs, bitmap, errp);
+
+    aio_context_release(aio_context);
+}
+
 BlockDirtyRangeList *qmp_query_block_dirty_bitmap_ranges(const char *node,
         const char *name, bool has_start, uint64_t start, bool has_count,
         uint64_t count, uint32_t max_ranges, bool has_block_io, bool block_io,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 89bdeaf..a83c286 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1238,6 +1238,42 @@
   'data': 'BlockDirtyBitmap' }
 
 ##
+# @block-dirty-bitmap-create-successor
+#
+# Interface to bdrv_dirty_bitmap_create_successor
+#
+# Returns: nothing on success
+#
+# Since 2.6
+##
+{ 'command': 'block-dirty-bitmap-create-successor',
+  'data': 'BlockDirtyBitmap' }
+
+##
+# @block-dirty-bitmap-abdicate
+#
+# Interface to bdrv_dirty_bitmap_abdicate
+#
+# Returns: nothing on success
+#
+# Since 2.6
+##
+{ 'command': 'block-dirty-bitmap-abdicate',
+  'data': 'BlockDirtyBitmap' }
+
+##
+# @block-dirty-bitmap-reclaim
+#
+# Interface to bdrv_reclaim_dirty_bitmap
+#
+# Returns: nothing on success
+#
+# Since 2.6
+##
+{ 'command': 'block-dirty-bitmap-reclaim',
+  'data': 'BlockDirtyBitmap' }
+
+##
 # @blockdev-mirror
 #
 # Start mirroring a block device's writes to a new destination.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 02de44c..6098371 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1457,6 +1457,91 @@ Example:
 EQMP
 
     {
+        .name       = "block-dirty-bitmap-create-successor",
+        .args_type  = "node:B,name:s",
+        .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_create_successor,
+    },
+
+SQMP
+
+block-dirty-bitmap-create-successor
+------------------------
+Since 2.6
+
+Create a successor bitmap destined to replace this bitmap after an operation.
+Requires that the bitmap is not frozen and has no successor.
+
+Arguments:
+
+- "node": device/node on which to remove dirty bitmap (json-string)
+- "name": name of the dirty bitmap to remove (json-string)
+
+Example:
+
+-> { "execute": "block-dirty-bitmap-create-successor",
+     "arguments": { "node": "drive0", "name": "bitmap0" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "block-dirty-bitmap-abdicate",
+        .args_type  = "node:B,name:s",
+        .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_abdicate,
+    },
+
+SQMP
+
+block-dirty-bitmap-abdicate
+------------------------
+Since 2.6
+
+For a bitmap with a successor, yield our name to the successor, delete the old
+bitmap, and return a handle to the new bitmap.
+
+Arguments:
+
+- "node": device/node on which to remove dirty bitmap (json-string)
+- "name": name of the dirty bitmap to remove (json-string)
+
+Example:
+
+-> { "execute": "block-dirty-bitmap-abdicate",
+     "arguments": { "node": "drive0", "name": "bitmap0" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "block-dirty-bitmap-reclaim",
+        .args_type  = "node:B,name:s",
+        .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_reclaim,
+    },
+
+SQMP
+
+block-dirty-bitmap-reclaim
+------------------------
+Since 2.6
+
+In cases of failure where we can no longer safely delete the parent, we may
+wish to re-join the parent and child/successor.  The merged parent will be
+un-frozen, but not explicitly re-enabled.
+
+Arguments:
+
+- "node": device/node on which to remove dirty bitmap (json-string)
+- "name": name of the dirty bitmap to remove (json-string)
+
+Example:
+
+-> { "execute": "block-dirty-bitmap-reclaim",
+     "arguments": { "node": "drive0", "name": "bitmap0" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "query-block-dirty-bitmap-ranges",
         .args_type  = "node:B,name:s,start:i?,count:i?,max-ranges:i,"
                       "block-io:b?",
