721 lines
21 KiB
Diff
721 lines
21 KiB
Diff
From 2afa718d59ef86879a9e34b4601a1f2658afa9ba Mon Sep 17 00:00:00 2001
|
|
From: Eric Blake <eblake@redhat.com>
|
|
Date: Tue, 2 Jun 2020 02:34:14 +0100
|
|
Subject: [PATCH 09/26] blockdev: Split off basic bitmap operations for
|
|
qemu-img
|
|
|
|
RH-Author: Eric Blake <eblake@redhat.com>
|
|
Message-id: <20200602023420.2133649-7-eblake@redhat.com>
|
|
Patchwork-id: 97073
|
|
O-Subject: [RHEL-AV-8.2.1 qemu-kvm PATCH 06/12] blockdev: Split off basic bitmap operations for qemu-img
|
|
Bugzilla: 1779893 1779904
|
|
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
|
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
|
Upcoming patches want to add some basic bitmap manipulation abilities
|
|
to qemu-img. But blockdev.o is too heavyweight to link into qemu-img
|
|
(among other things, it would drag in block jobs and transaction
|
|
support - qemu-img does offline manipulation, where atomicity is less
|
|
important because there are no concurrent modifications to compete
|
|
with), so it's time to split off the bare bones of what we will need
|
|
into a new file block/monitor/bitmap-qmp-cmds.o.
|
|
|
|
This is sufficient to expose 6 QMP commands for use by qemu-img (add,
|
|
remove, clear, enable, disable, merge), as well as move the three
|
|
helper functions touched in the previous patch. Regarding
|
|
MAINTAINERS, the new file is automatically part of block core, but
|
|
also makes sense as related to other dirty bitmap files.
|
|
|
|
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
|
Message-Id: <20200513011648.166876-6-eblake@redhat.com>
|
|
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
|
(cherry picked from commit bb4e58c6137e80129b955789dd4b66c1504f20dc)
|
|
|
|
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
|
|
|
|
Conflicts:
|
|
Makefile.objs - comment context
|
|
block/monitor/Makefile.objs - context: a2dde2f2 not backported
|
|
blockdev.c - context
|
|
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
|
|
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
|
|
---
|
|
MAINTAINERS | 1 +
|
|
Makefile.objs | 3 +-
|
|
block/monitor/Makefile.objs | 1 +
|
|
block/monitor/bitmap-qmp-cmds.c | 321 ++++++++++++++++++++++++++++++++++++++++
|
|
blockdev.c | 284 -----------------------------------
|
|
5 files changed, 324 insertions(+), 286 deletions(-)
|
|
create mode 100644 block/monitor/Makefile.objs
|
|
create mode 100644 block/monitor/bitmap-qmp-cmds.c
|
|
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index 3a81ac9..49d5d44 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -1875,6 +1875,7 @@ L: qemu-block@nongnu.org
|
|
S: Supported
|
|
F: include/qemu/hbitmap.h
|
|
F: include/block/dirty-bitmap.h
|
|
+F: block/monitor/bitmap-qmp-cmds.c
|
|
F: block/dirty-bitmap.c
|
|
F: block/qcow2-bitmap.c
|
|
F: migration/block-dirty-bitmap.c
|
|
diff --git a/Makefile.objs b/Makefile.objs
|
|
index 1a8f288..7404ef0 100644
|
|
--- a/Makefile.objs
|
|
+++ b/Makefile.objs
|
|
@@ -13,9 +13,8 @@ authz-obj-y = authz/
|
|
#######################################################################
|
|
# block-obj-y is code used by both qemu system emulation and qemu-img
|
|
|
|
-block-obj-y = nbd/
|
|
+block-obj-y = block/ block/monitor/ nbd/ scsi/
|
|
block-obj-y += block.o blockjob.o job.o
|
|
-block-obj-y += block/ scsi/
|
|
block-obj-y += qemu-io-cmds.o
|
|
block-obj-$(CONFIG_REPLICATION) += replication.o
|
|
|
|
diff --git a/block/monitor/Makefile.objs b/block/monitor/Makefile.objs
|
|
new file mode 100644
|
|
index 0000000..f0c7642
|
|
--- /dev/null
|
|
+++ b/block/monitor/Makefile.objs
|
|
@@ -0,0 +1 @@
|
|
+block-obj-y += bitmap-qmp-cmds.o
|
|
diff --git a/block/monitor/bitmap-qmp-cmds.c b/block/monitor/bitmap-qmp-cmds.c
|
|
new file mode 100644
|
|
index 0000000..9f11dee
|
|
--- /dev/null
|
|
+++ b/block/monitor/bitmap-qmp-cmds.c
|
|
@@ -0,0 +1,321 @@
|
|
+/*
|
|
+ * QEMU block dirty bitmap QMP commands
|
|
+ *
|
|
+ * Copyright (c) 2003-2008 Fabrice Bellard
|
|
+ *
|
|
+ * This work is licensed under the terms of the GNU GPL, version 2 or
|
|
+ * later. See the COPYING file in the top-level directory.
|
|
+ *
|
|
+ * This file incorporates work covered by the following copyright and
|
|
+ * permission notice:
|
|
+ *
|
|
+ * Copyright (c) 2003-2008 Fabrice Bellard
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
+ * of this software and associated documentation files (the "Software"), to deal
|
|
+ * in the Software without restriction, including without limitation the rights
|
|
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
+ * copies of the Software, and to permit persons to whom the Software is
|
|
+ * furnished to do so, subject to the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be included in
|
|
+ * all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
+ * THE SOFTWARE.
|
|
+ */
|
|
+
|
|
+#include "qemu/osdep.h"
|
|
+
|
|
+#include "block/block_int.h"
|
|
+#include "qapi/qapi-commands-block.h"
|
|
+#include "qapi/error.h"
|
|
+
|
|
+/**
|
|
+ * block_dirty_bitmap_lookup:
|
|
+ * Return a dirty bitmap (if present), after validating
|
|
+ * the node reference and bitmap names.
|
|
+ *
|
|
+ * @node: The name of the BDS node to search for bitmaps
|
|
+ * @name: The name of the bitmap to search for
|
|
+ * @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
|
|
+ * @errp: Output pointer for error information. Can be NULL.
|
|
+ *
|
|
+ * @return: A bitmap object on success, or NULL on failure.
|
|
+ */
|
|
+BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
|
|
+ const char *name,
|
|
+ BlockDriverState **pbs,
|
|
+ Error **errp)
|
|
+{
|
|
+ BlockDriverState *bs;
|
|
+ BdrvDirtyBitmap *bitmap;
|
|
+
|
|
+ if (!node) {
|
|
+ error_setg(errp, "Node cannot be NULL");
|
|
+ return NULL;
|
|
+ }
|
|
+ if (!name) {
|
|
+ error_setg(errp, "Bitmap name cannot be NULL");
|
|
+ return NULL;
|
|
+ }
|
|
+ bs = bdrv_lookup_bs(node, node, NULL);
|
|
+ if (!bs) {
|
|
+ error_setg(errp, "Node '%s' not found", node);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ bitmap = bdrv_find_dirty_bitmap(bs, name);
|
|
+ if (!bitmap) {
|
|
+ error_setg(errp, "Dirty bitmap '%s' not found", name);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (pbs) {
|
|
+ *pbs = bs;
|
|
+ }
|
|
+
|
|
+ return bitmap;
|
|
+}
|
|
+
|
|
+void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
|
+ bool has_granularity, uint32_t granularity,
|
|
+ bool has_persistent, bool persistent,
|
|
+ bool has_disabled, bool disabled,
|
|
+ Error **errp)
|
|
+{
|
|
+ BlockDriverState *bs;
|
|
+ BdrvDirtyBitmap *bitmap;
|
|
+ AioContext *aio_context;
|
|
+
|
|
+ if (!name || name[0] == '\0') {
|
|
+ error_setg(errp, "Bitmap name cannot be empty");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ bs = bdrv_lookup_bs(node, node, errp);
|
|
+ if (!bs) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ aio_context = bdrv_get_aio_context(bs);
|
|
+ aio_context_acquire(aio_context);
|
|
+
|
|
+ if (has_granularity) {
|
|
+ if (granularity < 512 || !is_power_of_2(granularity)) {
|
|
+ error_setg(errp, "Granularity must be power of 2 "
|
|
+ "and at least 512");
|
|
+ goto out;
|
|
+ }
|
|
+ } else {
|
|
+ /* Default to cluster size, if available: */
|
|
+ granularity = bdrv_get_default_bitmap_granularity(bs);
|
|
+ }
|
|
+
|
|
+ if (!has_persistent) {
|
|
+ persistent = false;
|
|
+ }
|
|
+
|
|
+ if (!has_disabled) {
|
|
+ disabled = false;
|
|
+ }
|
|
+
|
|
+ if (persistent &&
|
|
+ !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
|
|
+ {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
|
|
+ if (bitmap == NULL) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (disabled) {
|
|
+ bdrv_disable_dirty_bitmap(bitmap);
|
|
+ }
|
|
+
|
|
+ bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
|
|
+
|
|
+out:
|
|
+ aio_context_release(aio_context);
|
|
+}
|
|
+
|
|
+BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
|
|
+ bool release,
|
|
+ BlockDriverState **bitmap_bs,
|
|
+ Error **errp)
|
|
+{
|
|
+ BlockDriverState *bs;
|
|
+ BdrvDirtyBitmap *bitmap;
|
|
+ AioContext *aio_context;
|
|
+
|
|
+ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
+ if (!bitmap || !bs) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ aio_context = bdrv_get_aio_context(bs);
|
|
+ aio_context_acquire(aio_context);
|
|
+
|
|
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
|
|
+ errp)) {
|
|
+ aio_context_release(aio_context);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
|
|
+ bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
|
|
+ {
|
|
+ aio_context_release(aio_context);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (release) {
|
|
+ bdrv_release_dirty_bitmap(bitmap);
|
|
+ }
|
|
+
|
|
+ if (bitmap_bs) {
|
|
+ *bitmap_bs = bs;
|
|
+ }
|
|
+
|
|
+ aio_context_release(aio_context);
|
|
+ return release ? NULL : bitmap;
|
|
+}
|
|
+
|
|
+void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
|
+ Error **errp)
|
|
+{
|
|
+ block_dirty_bitmap_remove(node, name, true, NULL, errp);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Completely clear a bitmap, for the purposes of synchronizing a bitmap
|
|
+ * immediately after a full backup operation.
|
|
+ */
|
|
+void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
|
|
+ Error **errp)
|
|
+{
|
|
+ BdrvDirtyBitmap *bitmap;
|
|
+ BlockDriverState *bs;
|
|
+
|
|
+ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
+ if (!bitmap || !bs) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ bdrv_clear_dirty_bitmap(bitmap, NULL);
|
|
+}
|
|
+
|
|
+void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
|
|
+ Error **errp)
|
|
+{
|
|
+ BlockDriverState *bs;
|
|
+ BdrvDirtyBitmap *bitmap;
|
|
+
|
|
+ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
+ if (!bitmap) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ bdrv_enable_dirty_bitmap(bitmap);
|
|
+}
|
|
+
|
|
+void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
|
|
+ Error **errp)
|
|
+{
|
|
+ BlockDriverState *bs;
|
|
+ BdrvDirtyBitmap *bitmap;
|
|
+
|
|
+ bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
+ if (!bitmap) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ bdrv_disable_dirty_bitmap(bitmap);
|
|
+}
|
|
+
|
|
+BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
|
|
+ BlockDirtyBitmapMergeSourceList *bms,
|
|
+ HBitmap **backup, Error **errp)
|
|
+{
|
|
+ BlockDriverState *bs;
|
|
+ BdrvDirtyBitmap *dst, *src, *anon;
|
|
+ BlockDirtyBitmapMergeSourceList *lst;
|
|
+ Error *local_err = NULL;
|
|
+
|
|
+ dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
|
|
+ if (!dst) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
|
|
+ NULL, errp);
|
|
+ if (!anon) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ for (lst = bms; lst; lst = lst->next) {
|
|
+ switch (lst->value->type) {
|
|
+ const char *name, *node;
|
|
+ case QTYPE_QSTRING:
|
|
+ name = lst->value->u.local;
|
|
+ src = bdrv_find_dirty_bitmap(bs, name);
|
|
+ if (!src) {
|
|
+ error_setg(errp, "Dirty bitmap '%s' not found", name);
|
|
+ dst = NULL;
|
|
+ goto out;
|
|
+ }
|
|
+ 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) {
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Merge into dst; dst is unchanged on failure. */
|
|
+ bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
|
|
+
|
|
+ out:
|
|
+ bdrv_release_dirty_bitmap(anon);
|
|
+ return dst;
|
|
+}
|
|
+
|
|
+void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
|
|
+ BlockDirtyBitmapMergeSourceList *bitmaps,
|
|
+ Error **errp)
|
|
+{
|
|
+ block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
|
|
+}
|
|
diff --git a/blockdev.c b/blockdev.c
|
|
index 3958058..5128c9b 100644
|
|
--- a/blockdev.c
|
|
+++ b/blockdev.c
|
|
@@ -1250,53 +1250,6 @@ out_aio_context:
|
|
return NULL;
|
|
}
|
|
|
|
-/**
|
|
- * block_dirty_bitmap_lookup:
|
|
- * Return a dirty bitmap (if present), after validating
|
|
- * the node reference and bitmap names.
|
|
- *
|
|
- * @node: The name of the BDS node to search for bitmaps
|
|
- * @name: The name of the bitmap to search for
|
|
- * @pbs: Output pointer for BDS lookup, if desired. Can be NULL.
|
|
- * @errp: Output pointer for error information. Can be NULL.
|
|
- *
|
|
- * @return: A bitmap object on success, or NULL on failure.
|
|
- */
|
|
-BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node,
|
|
- const char *name,
|
|
- BlockDriverState **pbs,
|
|
- Error **errp)
|
|
-{
|
|
- BlockDriverState *bs;
|
|
- BdrvDirtyBitmap *bitmap;
|
|
-
|
|
- if (!node) {
|
|
- error_setg(errp, "Node cannot be NULL");
|
|
- return NULL;
|
|
- }
|
|
- if (!name) {
|
|
- error_setg(errp, "Bitmap name cannot be NULL");
|
|
- return NULL;
|
|
- }
|
|
- bs = bdrv_lookup_bs(node, node, NULL);
|
|
- if (!bs) {
|
|
- error_setg(errp, "Node '%s' not found", node);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- bitmap = bdrv_find_dirty_bitmap(bs, name);
|
|
- if (!bitmap) {
|
|
- error_setg(errp, "Dirty bitmap '%s' not found", name);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- if (pbs) {
|
|
- *pbs = bs;
|
|
- }
|
|
-
|
|
- return bitmap;
|
|
-}
|
|
-
|
|
/* New and old BlockDriverState structs for atomic group operations */
|
|
|
|
typedef struct BlkActionState BlkActionState;
|
|
@@ -2974,243 +2927,6 @@ out:
|
|
aio_context_release(aio_context);
|
|
}
|
|
|
|
-void qmp_block_dirty_bitmap_add(const char *node, const char *name,
|
|
- bool has_granularity, uint32_t granularity,
|
|
- bool has_persistent, bool persistent,
|
|
- bool has_disabled, bool disabled,
|
|
- Error **errp)
|
|
-{
|
|
- BlockDriverState *bs;
|
|
- BdrvDirtyBitmap *bitmap;
|
|
- AioContext *aio_context;
|
|
-
|
|
- if (!name || name[0] == '\0') {
|
|
- error_setg(errp, "Bitmap name cannot be empty");
|
|
- return;
|
|
- }
|
|
-
|
|
- bs = bdrv_lookup_bs(node, node, errp);
|
|
- if (!bs) {
|
|
- return;
|
|
- }
|
|
-
|
|
- aio_context = bdrv_get_aio_context(bs);
|
|
- aio_context_acquire(aio_context);
|
|
-
|
|
- if (has_granularity) {
|
|
- if (granularity < 512 || !is_power_of_2(granularity)) {
|
|
- error_setg(errp, "Granularity must be power of 2 "
|
|
- "and at least 512");
|
|
- goto out;
|
|
- }
|
|
- } else {
|
|
- /* Default to cluster size, if available: */
|
|
- granularity = bdrv_get_default_bitmap_granularity(bs);
|
|
- }
|
|
-
|
|
- if (!has_persistent) {
|
|
- persistent = false;
|
|
- }
|
|
-
|
|
- if (!has_disabled) {
|
|
- disabled = false;
|
|
- }
|
|
-
|
|
- if (persistent &&
|
|
- !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
|
|
- {
|
|
- goto out;
|
|
- }
|
|
-
|
|
- bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
|
|
- if (bitmap == NULL) {
|
|
- goto out;
|
|
- }
|
|
-
|
|
- if (disabled) {
|
|
- bdrv_disable_dirty_bitmap(bitmap);
|
|
- }
|
|
-
|
|
- bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
|
|
-
|
|
-out:
|
|
- aio_context_release(aio_context);
|
|
-}
|
|
-
|
|
-BdrvDirtyBitmap *block_dirty_bitmap_remove(const char *node, const char *name,
|
|
- bool release,
|
|
- BlockDriverState **bitmap_bs,
|
|
- Error **errp)
|
|
-{
|
|
- BlockDriverState *bs;
|
|
- BdrvDirtyBitmap *bitmap;
|
|
- AioContext *aio_context;
|
|
-
|
|
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
- if (!bitmap || !bs) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- aio_context = bdrv_get_aio_context(bs);
|
|
- aio_context_acquire(aio_context);
|
|
-
|
|
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
|
|
- errp)) {
|
|
- aio_context_release(aio_context);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- if (bdrv_dirty_bitmap_get_persistence(bitmap) &&
|
|
- bdrv_remove_persistent_dirty_bitmap(bs, name, errp) < 0)
|
|
- {
|
|
- aio_context_release(aio_context);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- if (release) {
|
|
- bdrv_release_dirty_bitmap(bitmap);
|
|
- }
|
|
-
|
|
- if (bitmap_bs) {
|
|
- *bitmap_bs = bs;
|
|
- }
|
|
-
|
|
- aio_context_release(aio_context);
|
|
- return release ? NULL : bitmap;
|
|
-}
|
|
-
|
|
-void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
|
|
- Error **errp)
|
|
-{
|
|
- block_dirty_bitmap_remove(node, name, true, NULL, errp);
|
|
-}
|
|
-
|
|
-/**
|
|
- * Completely clear a bitmap, for the purposes of synchronizing a bitmap
|
|
- * immediately after a full backup operation.
|
|
- */
|
|
-void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
|
|
- Error **errp)
|
|
-{
|
|
- BdrvDirtyBitmap *bitmap;
|
|
- BlockDriverState *bs;
|
|
-
|
|
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
- if (!bitmap || !bs) {
|
|
- return;
|
|
- }
|
|
-
|
|
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) {
|
|
- return;
|
|
- }
|
|
-
|
|
- bdrv_clear_dirty_bitmap(bitmap, NULL);
|
|
-}
|
|
-
|
|
-void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
|
|
- Error **errp)
|
|
-{
|
|
- BlockDriverState *bs;
|
|
- BdrvDirtyBitmap *bitmap;
|
|
-
|
|
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
- if (!bitmap) {
|
|
- return;
|
|
- }
|
|
-
|
|
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
|
|
- return;
|
|
- }
|
|
-
|
|
- bdrv_enable_dirty_bitmap(bitmap);
|
|
-}
|
|
-
|
|
-void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
|
|
- Error **errp)
|
|
-{
|
|
- BlockDriverState *bs;
|
|
- BdrvDirtyBitmap *bitmap;
|
|
-
|
|
- bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
|
|
- if (!bitmap) {
|
|
- return;
|
|
- }
|
|
-
|
|
- if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) {
|
|
- return;
|
|
- }
|
|
-
|
|
- bdrv_disable_dirty_bitmap(bitmap);
|
|
-}
|
|
-
|
|
-BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target,
|
|
- BlockDirtyBitmapMergeSourceList *bms,
|
|
- HBitmap **backup, Error **errp)
|
|
-{
|
|
- BlockDriverState *bs;
|
|
- BdrvDirtyBitmap *dst, *src, *anon;
|
|
- BlockDirtyBitmapMergeSourceList *lst;
|
|
- Error *local_err = NULL;
|
|
-
|
|
- dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
|
|
- if (!dst) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
|
|
- NULL, errp);
|
|
- if (!anon) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- for (lst = bms; lst; lst = lst->next) {
|
|
- switch (lst->value->type) {
|
|
- const char *name, *node;
|
|
- case QTYPE_QSTRING:
|
|
- name = lst->value->u.local;
|
|
- src = bdrv_find_dirty_bitmap(bs, name);
|
|
- if (!src) {
|
|
- error_setg(errp, "Dirty bitmap '%s' not found", name);
|
|
- dst = NULL;
|
|
- goto out;
|
|
- }
|
|
- 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) {
|
|
- 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;
|
|
- }
|
|
- }
|
|
-
|
|
- /* Merge into dst; dst is unchanged on failure. */
|
|
- bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
|
|
-
|
|
- out:
|
|
- bdrv_release_dirty_bitmap(anon);
|
|
- return dst;
|
|
-}
|
|
-
|
|
-void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
|
|
- BlockDirtyBitmapMergeSourceList *bitmaps,
|
|
- Error **errp)
|
|
-{
|
|
- block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
|
|
-}
|
|
-
|
|
BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
|
|
const char *name,
|
|
Error **errp)
|
|
--
|
|
1.8.3.1
|
|
|