From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: nsoffer@redhat.com, kwolf@redhat.com, jsnow@redhat.com,
qemu-block@nongnu.org, Max Reitz <mreitz@redhat.com>
Subject: [PATCH v2 3/6] qemu-img: Add bitmap sub-command
Date: Tue, 21 Apr 2020 16:20:16 -0500 [thread overview]
Message-ID: <20200421212019.170707-4-eblake@redhat.com> (raw)
In-Reply-To: <20200421212019.170707-1-eblake@redhat.com>
Include actions for --add, --remove, --clear, --enable, --disable, and
--merge (note that --clear is a bit of fluff, because the same can be
accomplished by removing a bitmap and then adding a new one in its
place, but it matches what QMP commands exist). Listing is omitted,
because it does not require a bitmap name and because it was already
possible with 'qemu-img info'. Merge can work either from another
bitmap in the same image, or from a bitmap in a distinct image.
While this supports --image-opts for the file being modified, I did
not think it worth the extra complexity to support that for the source
file in a cross-file bitmap merge. Likewise, I chose to have --merge
only take a single source rather than following the QMP support for
multiple merges in one go; in part to simplify the command line, and
in part because an offline image can achieve the same effect by
multiple qemu-img bitmap --merge calls. We can enhance that if needed
in the future (the same way that 'qemu-img convert' has a mode that
concatenates multiple sources into one destination).
Upcoming patches will add iotest coverage of these commands while
also testing other features.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
docs/tools/qemu-img.rst | 24 +++++
qemu-img.c | 198 ++++++++++++++++++++++++++++++++++++++++
qemu-img-cmds.hx | 7 ++
3 files changed, 229 insertions(+)
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 7d08c48d308f..4f3b0e2c9ace 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -281,6 +281,30 @@ Command description:
For write tests, by default a buffer filled with zeros is written. This can be
overridden with a pattern byte specified by *PATTERN*.
+.. option:: bitmap {--add [-g GRANULARITY] [--disabled] | --remove | --clear | --enable | --disable | --merge SOURCE_BITMAP [-b SOURCE_FILE [-F SOURCE_FMT]]} [--object OBJECTDEF] [--image-opts] [-f FMT] FILENAME BITMAP
+
+ Perform a modification of the persistent bitmap *BITMAP* in the disk
+ image *FILENAME*. The various modifications are:
+
+ ``--add`` to create *BITMAP*, with additional options ``-g`` to
+ specify a non-default *GRANULARITY*, or whether the bitmap should be
+ ``--disabled`` instead of enabled.
+
+ ``--remove`` to remove *BITMAP*.
+
+ ``--clear`` to clear *BITMAP*.
+
+ ``--enable`` to change *BITMAP* to start recording future edits.
+
+ ``--disable`` to change *BITMAP* to stop recording future edits.
+
+ ``--merge`` to merge the contents of *SOURCE_BITMAP* into *BITMAP*.
+ This defaults to requiring a source bitmap from the same *FILENAME*,
+ but can also be used for cross-image merge by supplying ``-b`` to
+ specify a different *SOURCE_FILE*.
+
+ To see what bitmaps are present in an image, use ``qemu-img info``.
+
.. option:: check [--object OBJECTDEF] [--image-opts] [-q] [-f FMT] [--output=OFMT] [-r [leaks | all]] [-T SRC_CACHE] [-U] FILENAME
Perform a consistency check on the disk image *FILENAME*. The command can
diff --git a/qemu-img.c b/qemu-img.c
index 821cbf610e5f..02ebd870faa1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -28,6 +28,7 @@
#include "qemu-common.h"
#include "qemu-version.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-block-core.h"
#include "qapi/qapi-visit-block-core.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp/qjson.h"
@@ -71,6 +72,12 @@ enum {
OPTION_SHRINK = 266,
OPTION_SALVAGE = 267,
OPTION_TARGET_IS_ZERO = 268,
+ OPTION_ADD = 269,
+ OPTION_REMOVE = 270,
+ OPTION_CLEAR = 271,
+ OPTION_ENABLE = 272,
+ OPTION_DISABLE = 273,
+ OPTION_MERGE = 274,
};
typedef enum OutputFormat {
@@ -4438,6 +4445,197 @@ out:
return 0;
}
+static int img_bitmap(int argc, char **argv)
+{
+ Error *err = NULL;
+ int c, ret = -1;
+ QemuOpts *opts = NULL;
+ const char *fmt = NULL, *src_fmt = NULL, *src_filename = NULL;
+ const char *filename, *bitmap;
+ BlockBackend *blk = NULL, *src = NULL;
+ BlockDriverState *bs = NULL, *src_bs = NULL;
+ bool image_opts = false;
+ unsigned long granularity = 0;
+ bool add = false, remove = false, clear = false;
+ bool enable = false, disable = false, add_disabled = false;
+ const char *merge = NULL;
+
+ for (;;) {
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"object", required_argument, 0, OPTION_OBJECT},
+ {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"add", no_argument, 0, OPTION_ADD},
+ {"remove", no_argument, 0, OPTION_REMOVE},
+ {"clear", no_argument, 0, OPTION_CLEAR},
+ {"enable", no_argument, 0, OPTION_ENABLE},
+ {"disable", no_argument, 0, OPTION_DISABLE},
+ {"disabled", no_argument, 0, OPTION_DISABLE},
+ {"merge", required_argument, 0, OPTION_MERGE},
+ {"granularity", required_argument, 0, 'g'},
+ {"source-file", required_argument, 0, 'b'},
+ {"source-format", required_argument, 0, 'F'},
+ {0, 0, 0, 0}
+ };
+ c = getopt_long(argc, argv, ":b:f:F:g:h", long_options, NULL);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case ':':
+ missing_argument(argv[optind - 1]);
+ break;
+ case '?':
+ unrecognized_option(argv[optind - 1]);
+ break;
+ case 'h':
+ help();
+ break;
+ case 'b':
+ src_filename = optarg;
+ break;
+ case 'f':
+ fmt = optarg;
+ break;
+ case 'F':
+ src_fmt = optarg;
+ break;
+ case 'g':
+ if (qemu_strtosz(optarg, NULL, &granularity)) {
+ error_report("Invalid granularity specified");
+ return 1;
+ }
+ break;
+ case OPTION_ADD:
+ add = true;
+ break;
+ case OPTION_REMOVE:
+ remove = true;
+ break;
+ case OPTION_CLEAR:
+ clear = true;
+ break;
+ case OPTION_ENABLE:
+ enable = true;
+ break;
+ case OPTION_DISABLE:
+ disable = true;
+ break;
+ case OPTION_MERGE:
+ merge = optarg;
+ break;
+ case OPTION_OBJECT:
+ opts = qemu_opts_parse_noisily(&qemu_object_opts,
+ optarg, true);
+ if (!opts) {
+ goto out;
+ }
+ break;
+ case OPTION_IMAGE_OPTS:
+ image_opts = true;
+ break;
+ }
+ }
+
+ if (qemu_opts_foreach(&qemu_object_opts,
+ user_creatable_add_opts_foreach,
+ qemu_img_object_print_help, &error_fatal)) {
+ goto out;
+ }
+
+ if (add && disable) {
+ disable = false;
+ add_disabled = true;
+ }
+ if (add + remove + clear + enable + disable + !!merge != 1) {
+ error_report("Need exactly one mode of --add, --remove, --clear, "
+ "--enable, --disable, or --merge");
+ goto out;
+ }
+ if (granularity && !add) {
+ error_report("granularity only supported with --add");
+ goto out;
+ }
+ if (src_fmt && !src_filename) {
+ error_report("-F only supported with -b");
+ goto out;
+ }
+ if (src_filename && !merge) {
+ error_report("alternate source file only supported with --merge");
+ goto out;
+ }
+
+ if (optind != argc - 2) {
+ error_report("Expecting filename and bitmap name");
+ goto out;
+ }
+
+ filename = argv[optind];
+ bitmap = argv[optind + 1];
+
+ blk = img_open(image_opts, filename, fmt, BDRV_O_RDWR, false, false,
+ false);
+ if (!blk) {
+ goto out;
+ }
+ bs = blk_bs(blk);
+
+ if (add) {
+ qmp_block_dirty_bitmap_add(bs->node_name, bitmap,
+ !!granularity, granularity, true, true,
+ true, add_disabled, &err);
+ } else if (remove) {
+ qmp_block_dirty_bitmap_remove(bs->node_name, bitmap, &err);
+ } else if (clear) {
+ qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
+ } else if (enable) {
+ qmp_block_dirty_bitmap_enable(bs->node_name, bitmap, &err);
+ } else if (disable) {
+ qmp_block_dirty_bitmap_disable(bs->node_name, bitmap, &err);
+ } else if (merge) {
+ BlockDirtyBitmapMergeSource *merge_src;
+ BlockDirtyBitmapMergeSourceList *list;
+
+ if (src_filename) {
+ src = img_open(NULL, src_filename, src_fmt, 0, false, false,
+ false);
+ if (!src) {
+ goto out;
+ }
+ src_bs = blk_bs(src);
+ } else {
+ src_bs = bs;
+ }
+
+ merge_src = g_new0(BlockDirtyBitmapMergeSource, 1);
+ merge_src->type = QTYPE_QDICT;
+ merge_src->u.external.node = g_strdup(src_bs->node_name);
+ merge_src->u.external.name = g_strdup(merge);
+ list = g_new0(BlockDirtyBitmapMergeSourceList, 1);
+ list->value = merge_src;
+ qmp_block_dirty_bitmap_merge(bs->node_name, bitmap, list, &err);
+ qapi_free_BlockDirtyBitmapMergeSourceList(list);
+ }
+
+ if (err) {
+ error_reportf_err(err, "Bitmap %s operation failed", bitmap);
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+
+ out:
+ blk_unref(src);
+ blk_unref(blk);
+ qemu_opts_del(opts);
+ if (ret) {
+ return 1;
+ }
+ return 0;
+}
+
#define C_BS 01
#define C_COUNT 02
#define C_IF 04
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index c9c54de1df40..bf0035e226c8 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -20,6 +20,13 @@ DEF("bench", img_bench,
SRST
.. option:: bench [-c COUNT] [-d DEPTH] [-f FMT] [--flush-interval=FLUSH_INTERVAL] [-i AIO] [-n] [--no-drain] [-o OFFSET] [--pattern=PATTERN] [-q] [-s BUFFER_SIZE] [-S STEP_SIZE] [-t CACHE] [-w] [-U] FILENAME
ERST
+
+DEF("bitmap", img_bitmap,
+ "bitmap {--add [-g granularity] [--disabled] | --remove | --clear | --enable | --disable | --merge source_bitmap [-b source_file [-F source_fmt]]} [--object objectdef] [--image-opts] [-f fmt] filename bitmap")
+SRST
+.. option:: bitmap {--add [-g GRANULARITY] [--disabled] | --remove | --clear | --enable | --disable | --merge SOURCE_BITMAP [-b SOURCE_FILE [-F SOURCE_FMT]]} [--object OBJECTDEF] [--image-opts] [-f FMT] FILENAME BITMAP
+ERST
+
DEF("check", img_check,
"check [--object objectdef] [--image-opts] [-q] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] [-U] filename")
SRST
--
2.26.2
next prev parent reply other threads:[~2020-04-21 21:25 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-21 21:20 [PATCH v2 0/6] qemu-img: Add convert --bitmaps Eric Blake
2020-04-21 21:20 ` [PATCH v2 1/6] docs: Sort sections on qemu-img subcommand parameters Eric Blake
2020-04-30 12:50 ` Max Reitz
2020-04-21 21:20 ` [PATCH v2 2/6] blockdev: Split off basic bitmap operations for qemu-img Eric Blake
2020-04-30 13:59 ` Max Reitz
2020-04-30 14:50 ` Eric Blake
2020-05-08 11:37 ` Kevin Wolf
2020-05-08 13:48 ` Eric Blake
2020-04-21 21:20 ` Eric Blake [this message]
2020-04-30 14:55 ` [PATCH v2 3/6] qemu-img: Add bitmap sub-command Max Reitz
2020-04-30 15:21 ` Eric Blake
2020-05-04 10:01 ` Max Reitz
2020-05-04 13:28 ` Eric Blake
2020-04-21 21:20 ` [PATCH v2 4/6] qcow2: Expose bitmaps' size during measure Eric Blake
2020-05-04 11:36 ` Max Reitz
2020-05-04 13:44 ` Eric Blake
2020-04-21 21:20 ` [PATCH v2 5/6] qemu-img: Add convert --bitmaps option Eric Blake
2020-05-04 12:14 ` Max Reitz
2020-04-21 21:20 ` [PATCH v2 6/6] iotests: Add test 291 to for qemu-img bitmap coverage Eric Blake
2020-05-04 13:05 ` Max Reitz
2020-05-05 21:22 ` Eric Blake
2020-04-21 22:22 ` [PATCH v2 0/6] qemu-img: Add convert --bitmaps no-reply
2020-04-21 22:49 ` [PATCH] fixup! qemu-img: Add bitmap sub-command Eric Blake
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200421212019.170707-4-eblake@redhat.com \
--to=eblake@redhat.com \
--cc=jsnow@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=nsoffer@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).