From time to time it is needed to remove all bitmaps from the image.
Before this patch the process is not very convinient. One should
perform
qemu-img info
and parse the output to obtain all names. After that one should
sequentially call
qemu-img bitmap --remove
for each present bitmap.
The patch adds --remove-all sub-command to 'qemu-img bitmap'.
Signed-off-by: Denis V. Lunev <d...@openvz.org>
CC: Kevin Wolf <kw...@redhat.com>
CC: Hanna Reitz <hre...@redhat.com>
CC: Michael Tokarev <m...@tls.msk.ru>
---
Changes from v1:
* rebased to latest head
* adopted bitmap help to the new layout
docs/tools/qemu-img.rst | 4 +++-
qemu-img.c | 47 ++++++++++++++++++++++++++++++++++-------
2 files changed, 42 insertions(+), 9 deletions(-)
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 5e7b85079d..db739ab5c8 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -301,7 +301,7 @@ 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 (--merge SOURCE | --add | --remove | --clear | --enable | --disable)... [-b SOURCE_FILE [-F SOURCE_FMT]] [-g GRANULARITY] [--object OBJECTDEF] [--image-opts | -f FMT] FILENAME BITMAP
+.. option:: bitmap (--merge SOURCE | --add | --remove | --remove-all | --clear
| --enable | --disable)... [-b SOURCE_FILE [-F SOURCE_FMT]] [-g GRANULARITY]
[--object OBJECTDEF] [--image-opts | -f FMT] FILENAME BITMAP
Perform one or more modifications of the persistent bitmap *BITMAP*
in the disk image *FILENAME*. The various modifications are:
@@ -310,6 +310,8 @@ Command description:
``--remove`` to remove *BITMAP*.
+ ``--remove-all`` to remove all bitmaps.
+
``--clear`` to clear *BITMAP*.
``--enable`` to change *BITMAP* to start recording future edits.
diff --git a/qemu-img.c b/qemu-img.c
index 7a162fdc08..ddd449c1ed 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -86,6 +86,7 @@ enum {
OPTION_BITMAPS = 275,
OPTION_FORCE = 276,
OPTION_SKIP_BROKEN = 277,
+ OPTION_REMOVE_ALL = 278,
};
typedef enum OutputFormat {
@@ -4992,6 +4993,7 @@ enum ImgBitmapAct {
BITMAP_ENABLE,
BITMAP_DISABLE,
BITMAP_MERGE,
+ BITMAP_REMOVE_ALL,
};
typedef struct ImgBitmapAction {
enum ImgBitmapAct act;
@@ -5010,7 +5012,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
BlockDriverState *bs = NULL, *src_bs = NULL;
bool image_opts = false;
int64_t granularity = 0;
- bool add = false, merge = false;
+ bool add = false, merge = false, remove_all = false, any = false;
QSIMPLEQ_HEAD(, ImgBitmapAction) actions;
ImgBitmapAction *act, *act_next;
const char *op;
@@ -5026,6 +5028,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
{"add", no_argument, 0, OPTION_ADD},
{"granularity", required_argument, 0, 'g'},
{"remove", no_argument, 0, OPTION_REMOVE},
+ {"remove-all", no_argument, 0, OPTION_REMOVE_ALL},
{"clear", no_argument, 0, OPTION_CLEAR},
{"enable", no_argument, 0, OPTION_ENABLE},
{"disable", no_argument, 0, OPTION_DISABLE},
@@ -5044,8 +5047,8 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
switch (c) {
case 'h':
cmd_help(ccmd, "[-f FMT | --image-opts]\n"
-" ( --add [-g SIZE] | --remove | --clear | --enable | --disable |\n"
-" --merge SOURCE [-b SRC_FILE [-F SRC_FMT]] )..\n"
+" ( --add [-g SIZE] | --remove | --remove-all | --clear | --enable |\n"
+" --disable | --merge SOURCE [-b SRC_FILE [-F SRC_FMT]] )..\n"
" [--object OBJDEF] FILE BITMAP\n"
,
" -f, --format FMT\n"
@@ -5060,6 +5063,8 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
" with optional multiplier suffix (in powers of 1024)\n"
" --remove\n"
" removes BITMAP from FILE\n"
+" --remove-all\n"
+" removes all bitmaps from FILE\n"
" --clear\n"
" clears BITMAP in FILE\n"
" --enable, --disable\n"
@@ -5089,7 +5094,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_ADD;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
- add = true;
+ add = any = true;
break;
case 'g':
granularity = cvtnum("granularity", optarg, true);
@@ -5101,28 +5106,38 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_REMOVE;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ any = true;
+ break;
+ case OPTION_REMOVE_ALL:
+ act = g_new0(ImgBitmapAction, 1);
+ act->act = BITMAP_REMOVE_ALL;
+ QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ remove_all = true;
break;
case OPTION_CLEAR:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_CLEAR;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ any = true;
break;
case OPTION_ENABLE:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_ENABLE;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ any = true;
break;
case OPTION_DISABLE:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_DISABLE;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ any = true;
break;
case OPTION_MERGE:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_MERGE;
act->src = optarg;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
- merge = true;
+ any = merge = true;
break;
case 'b':
src_filename = optarg;
@@ -5139,8 +5154,8 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
}
if (QSIMPLEQ_EMPTY(&actions)) {
- error_report("Need at least one of --add, --remove, --clear, "
- "--enable, --disable, or --merge");
+ error_report("Need at least one of --add, --remove, --remove-all, "
+ "--clear, --enable, --disable, or --merge");
goto out;
}
@@ -5158,10 +5173,14 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
goto out;
}
- if (optind != argc - 2) {
+ if (any && optind != argc - 2) {
error_report("Expecting filename and bitmap name");
goto out;
}
+ if (!any && remove_all && optind != argc - 1) {
+ error_report("Expecting filename");
+ goto out;
+ }
filename = argv[optind];
bitmap = argv[optind + 1];
@@ -5199,6 +5218,18 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc,
char **argv)
qmp_block_dirty_bitmap_remove(bs->node_name, bitmap, &err);
op = "remove";
break;
+ case BITMAP_REMOVE_ALL: {
+ while (1) {
+ BdrvDirtyBitmap *bm = bdrv_dirty_bitmap_first(bs);
+ if (bm == NULL) {
+ break;
+ }
+ qmp_block_dirty_bitmap_remove(bs->node_name,
+ bdrv_dirty_bitmap_name(bm),
&err);
+ }
+ op = "remove-all";
+ break;
+ }
case BITMAP_CLEAR:
qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
op = "clear";