* [PATCH v3 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
@ 2026-04-24 10:59 Denis V. Lunev via qemu development
2026-05-11 21:53 ` Denis V. Lunev
2026-05-15 13:55 ` Kevin Wolf
0 siblings, 2 replies; 4+ messages in thread
From: Denis V. Lunev via qemu development @ 2026-04-24 10:59 UTC (permalink / raw)
To: qemu-devel; +Cc: qemu-block, Denis V. Lunev, Kevin Wolf, Hanna Reitz
From time to time it is needed to remove all bitmaps from the image.
Before this patch the process is not very convenient. 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 <den@openvz.org>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Hanna Reitz <hreitz@redhat.com>
---
Changes from v2:
* rebased to the lastest head
Changes from v1:
* rebased to latest head
* adopted bitmap help to the new layout
docs/tools/qemu-img.rst | 10 +++++---
qemu-img.c | 53 ++++++++++++++++++++++++++++++++++-------
2 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 558b0eb84d..b0c798b77a 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -301,15 +301,19 @@ 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:
+ Perform one or more modifications of persistent bitmaps in the disk
+ image *FILENAME*. Most operations require *BITMAP* to be specified;
+ ``--remove-all`` operates on all bitmaps and does not take *BITMAP*.
+ The various modifications are:
``--add`` to create *BITMAP*, enabled to record future edits.
``--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 c42dd4e995..22ddc7a627 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -87,6 +87,7 @@ enum {
OPTION_FORCE = 276,
OPTION_SKIP_BROKEN = 277,
OPTION_LIMITS = 278,
+ OPTION_REMOVE_ALL = 279,
};
typedef enum OutputFormat {
@@ -5018,6 +5019,7 @@ enum ImgBitmapAct {
BITMAP_ENABLE,
BITMAP_DISABLE,
BITMAP_MERGE,
+ BITMAP_REMOVE_ALL,
};
typedef struct ImgBitmapAction {
enum ImgBitmapAct act;
@@ -5036,7 +5038,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;
@@ -5052,6 +5054,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},
@@ -5070,8 +5073,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"
@@ -5086,6 +5089,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"
@@ -5115,7 +5120,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);
@@ -5127,28 +5132,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;
@@ -5165,8 +5180,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;
}
@@ -5184,10 +5199,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];
@@ -5225,6 +5244,24 @@ 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) {
+ const char *name;
+ BdrvDirtyBitmap *bm = bdrv_dirty_bitmap_first(bs);
+ if (bm == NULL) {
+ break;
+ }
+ name = bdrv_dirty_bitmap_name(bm);
+ qmp_block_dirty_bitmap_remove(bs->node_name, name, &err);
+ if (err) {
+ /* Save name for proper error reporting */
+ bitmap = name;
+ break;
+ }
+ }
+ op = "remove-all";
+ break;
+ }
case BITMAP_CLEAR:
qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
op = "clear";
--
2.51.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v3 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
2026-04-24 10:59 [PATCH v3 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap' Denis V. Lunev via qemu development
@ 2026-05-11 21:53 ` Denis V. Lunev
2026-05-15 13:55 ` Kevin Wolf
1 sibling, 0 replies; 4+ messages in thread
From: Denis V. Lunev @ 2026-05-11 21:53 UTC (permalink / raw)
To: Denis V. Lunev, qemu-devel; +Cc: qemu-block, Kevin Wolf, Hanna Reitz
On 4/24/26 12:59, Denis V. Lunev wrote:
> From time to time it is needed to remove all bitmaps from the image.
> Before this patch the process is not very convenient. 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 <den@openvz.org>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Hanna Reitz <hreitz@redhat.com>
> ---
> Changes from v2:
> * rebased to the lastest head
>
> Changes from v1:
> * rebased to latest head
> * adopted bitmap help to the new layout
>
> docs/tools/qemu-img.rst | 10 +++++---
> qemu-img.c | 53 ++++++++++++++++++++++++++++++++++-------
> 2 files changed, 52 insertions(+), 11 deletions(-)
>
> diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
> index 558b0eb84d..b0c798b77a 100644
> --- a/docs/tools/qemu-img.rst
> +++ b/docs/tools/qemu-img.rst
> @@ -301,15 +301,19 @@ 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:
> + Perform one or more modifications of persistent bitmaps in the disk
> + image *FILENAME*. Most operations require *BITMAP* to be specified;
> + ``--remove-all`` operates on all bitmaps and does not take *BITMAP*.
> + The various modifications are:
>
> ``--add`` to create *BITMAP*, enabled to record future edits.
>
> ``--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 c42dd4e995..22ddc7a627 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -87,6 +87,7 @@ enum {
> OPTION_FORCE = 276,
> OPTION_SKIP_BROKEN = 277,
> OPTION_LIMITS = 278,
> + OPTION_REMOVE_ALL = 279,
> };
>
> typedef enum OutputFormat {
> @@ -5018,6 +5019,7 @@ enum ImgBitmapAct {
> BITMAP_ENABLE,
> BITMAP_DISABLE,
> BITMAP_MERGE,
> + BITMAP_REMOVE_ALL,
> };
> typedef struct ImgBitmapAction {
> enum ImgBitmapAct act;
> @@ -5036,7 +5038,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;
> @@ -5052,6 +5054,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},
> @@ -5070,8 +5073,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"
> @@ -5086,6 +5089,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"
> @@ -5115,7 +5120,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);
> @@ -5127,28 +5132,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;
> @@ -5165,8 +5180,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;
> }
>
> @@ -5184,10 +5199,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];
> @@ -5225,6 +5244,24 @@ 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) {
> + const char *name;
> + BdrvDirtyBitmap *bm = bdrv_dirty_bitmap_first(bs);
> + if (bm == NULL) {
> + break;
> + }
> + name = bdrv_dirty_bitmap_name(bm);
> + qmp_block_dirty_bitmap_remove(bs->node_name, name, &err);
> + if (err) {
> + /* Save name for proper error reporting */
> + bitmap = name;
> + break;
> + }
> + }
> + op = "remove-all";
> + break;
> + }
> case BITMAP_CLEAR:
> qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
> op = "clear";
ping
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v3 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
2026-04-24 10:59 [PATCH v3 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap' Denis V. Lunev via qemu development
2026-05-11 21:53 ` Denis V. Lunev
@ 2026-05-15 13:55 ` Kevin Wolf
2026-05-20 23:28 ` Denis V. Lunev
1 sibling, 1 reply; 4+ messages in thread
From: Kevin Wolf @ 2026-05-15 13:55 UTC (permalink / raw)
To: Denis V. Lunev; +Cc: qemu-devel, qemu-block, Hanna Reitz
Am 24.04.2026 um 12:59 hat Denis V. Lunev geschrieben:
> From time to time it is needed to remove all bitmaps from the image.
> Before this patch the process is not very convenient. 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 <den@openvz.org>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Hanna Reitz <hreitz@redhat.com>
> ---
> Changes from v2:
> * rebased to the lastest head
>
> Changes from v1:
> * rebased to latest head
> * adopted bitmap help to the new layout
>
> docs/tools/qemu-img.rst | 10 +++++---
> qemu-img.c | 53 ++++++++++++++++++++++++++++++++++-------
> 2 files changed, 52 insertions(+), 11 deletions(-)
>
> diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
> index 558b0eb84d..b0c798b77a 100644
> --- a/docs/tools/qemu-img.rst
> +++ b/docs/tools/qemu-img.rst
> @@ -301,15 +301,19 @@ 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:
> + Perform one or more modifications of persistent bitmaps in the disk
> + image *FILENAME*. Most operations require *BITMAP* to be specified;
> + ``--remove-all`` operates on all bitmaps and does not take *BITMAP*.
> + The various modifications are:
>
> ``--add`` to create *BITMAP*, enabled to record future edits.
>
> ``--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 c42dd4e995..22ddc7a627 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -87,6 +87,7 @@ enum {
> OPTION_FORCE = 276,
> OPTION_SKIP_BROKEN = 277,
> OPTION_LIMITS = 278,
> + OPTION_REMOVE_ALL = 279,
> };
>
> typedef enum OutputFormat {
> @@ -5018,6 +5019,7 @@ enum ImgBitmapAct {
> BITMAP_ENABLE,
> BITMAP_DISABLE,
> BITMAP_MERGE,
> + BITMAP_REMOVE_ALL,
> };
> typedef struct ImgBitmapAction {
> enum ImgBitmapAct act;
> @@ -5036,7 +5038,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;
It's quite unclear what "any" is supposed to mean. From the code it
looks like it's set when a bitmap name must be specified (which is the
opposite of what I'd think of with "any").
Can we use something more descriptive like need_bitmap_name?
> QSIMPLEQ_HEAD(, ImgBitmapAction) actions;
> ImgBitmapAction *act, *act_next;
> const char *op;
> @@ -5052,6 +5054,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},
> @@ -5070,8 +5073,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"
> @@ -5086,6 +5089,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"
> @@ -5115,7 +5120,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;
One assignment per line, please.
> break;
> case 'g':
> granularity = cvtnum("granularity", optarg, true);
> @@ -5127,28 +5132,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;
Same here.
> break;
> case 'b':
> src_filename = optarg;
> @@ -5165,8 +5180,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;
> }
>
> @@ -5184,10 +5199,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) {
Doesn't !any already imply remove_all? If both weren't set, actions
would be empty and we'd already have errored out above.
This probably means that remove_all can go away entirely because it's
only read in this condition.
> + error_report("Expecting filename");
> + goto out;
> + }
>
> filename = argv[optind];
> bitmap = argv[optind + 1];
> @@ -5225,6 +5244,24 @@ 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) {
> + const char *name;
> + BdrvDirtyBitmap *bm = bdrv_dirty_bitmap_first(bs);
> + if (bm == NULL) {
> + break;
> + }
while ((bm = bdrv_dirty_bitmap_first(bs)))?
> + name = bdrv_dirty_bitmap_name(bm);
> + qmp_block_dirty_bitmap_remove(bs->node_name, name, &err);
> + if (err) {
> + /* Save name for proper error reporting */
> + bitmap = name;
> + break;
> + }
> + }
> + op = "remove-all";
> + break;
> + }
> case BITMAP_CLEAR:
> qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
> op = "clear";
Kevin
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v3 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
2026-05-15 13:55 ` Kevin Wolf
@ 2026-05-20 23:28 ` Denis V. Lunev
0 siblings, 0 replies; 4+ messages in thread
From: Denis V. Lunev @ 2026-05-20 23:28 UTC (permalink / raw)
To: Kevin Wolf, Denis V. Lunev; +Cc: qemu-devel, qemu-block, Hanna Reitz
On 5/15/26 15:55, Kevin Wolf wrote:
> Am 24.04.2026 um 12:59 hat Denis V. Lunev geschrieben:
>> From time to time it is needed to remove all bitmaps from the image.
>> Before this patch the process is not very convenient. 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 <den@openvz.org>
>> CC: Kevin Wolf <kwolf@redhat.com>
>> CC: Hanna Reitz <hreitz@redhat.com>
>> ---
>> Changes from v2:
>> * rebased to the lastest head
>>
>> Changes from v1:
>> * rebased to latest head
>> * adopted bitmap help to the new layout
>>
>> docs/tools/qemu-img.rst | 10 +++++---
>> qemu-img.c | 53 ++++++++++++++++++++++++++++++++++-------
>> 2 files changed, 52 insertions(+), 11 deletions(-)
>>
>> diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
>> index 558b0eb84d..b0c798b77a 100644
>> --- a/docs/tools/qemu-img.rst
>> +++ b/docs/tools/qemu-img.rst
>> @@ -301,15 +301,19 @@ 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:
>> + Perform one or more modifications of persistent bitmaps in the disk
>> + image *FILENAME*. Most operations require *BITMAP* to be specified;
>> + ``--remove-all`` operates on all bitmaps and does not take *BITMAP*.
>> + The various modifications are:
>>
>> ``--add`` to create *BITMAP*, enabled to record future edits.
>>
>> ``--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 c42dd4e995..22ddc7a627 100644
>> --- a/qemu-img.c
>> +++ b/qemu-img.c
>> @@ -87,6 +87,7 @@ enum {
>> OPTION_FORCE = 276,
>> OPTION_SKIP_BROKEN = 277,
>> OPTION_LIMITS = 278,
>> + OPTION_REMOVE_ALL = 279,
>> };
>>
>> typedef enum OutputFormat {
>> @@ -5018,6 +5019,7 @@ enum ImgBitmapAct {
>> BITMAP_ENABLE,
>> BITMAP_DISABLE,
>> BITMAP_MERGE,
>> + BITMAP_REMOVE_ALL,
>> };
>> typedef struct ImgBitmapAction {
>> enum ImgBitmapAct act;
>> @@ -5036,7 +5038,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;
> It's quite unclear what "any" is supposed to mean. From the code it
> looks like it's set when a bitmap name must be specified (which is the
> opposite of what I'd think of with "any").
>
> Can we use something more descriptive like need_bitmap_name?
correct. I have spent at least 5 minutes trying to guess
what I mean under this name. Meaning was "any single bitmap
operation has been added to the list".
Actually non-obvious naming long term. This is good catch.
need_bitmap_name is nice.
>> QSIMPLEQ_HEAD(, ImgBitmapAction) actions;
>> ImgBitmapAction *act, *act_next;
>> const char *op;
>> @@ -5052,6 +5054,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},
>> @@ -5070,8 +5073,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"
>> @@ -5086,6 +5089,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"
>> @@ -5115,7 +5120,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;
> One assignment per line, please.
>
>> break;
>> case 'g':
>> granularity = cvtnum("granularity", optarg, true);
>> @@ -5127,28 +5132,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;
> Same here.
>
>> break;
>> case 'b':
>> src_filename = optarg;
>> @@ -5165,8 +5180,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;
>> }
>>
>> @@ -5184,10 +5199,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) {
> Doesn't !any already imply remove_all? If both weren't set, actions
> would be empty and we'd already have errored out above.
>
> This probably means that remove_all can go away entirely because it's
> only read in this condition.
Correct. We have had a check that at least one action is specified
if (QSIMPLEQ_EMPTY(&actions)) {
error_report("Need at least one of --add, --remove, --remove-all, "
"--clear, --enable, --disable, or --merge");
goto out;
}
and thus !any de-facto means that --remove-all is set and there
are no other actions added.
>> + error_report("Expecting filename");
>> + goto out;
>> + }
>>
>> filename = argv[optind];
>> bitmap = argv[optind + 1];
>> @@ -5225,6 +5244,24 @@ 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) {
>> + const char *name;
>> + BdrvDirtyBitmap *bm = bdrv_dirty_bitmap_first(bs);
>> + if (bm == NULL) {
>> + break;
>> + }
> while ((bm = bdrv_dirty_bitmap_first(bs)))?
>
>> + name = bdrv_dirty_bitmap_name(bm);
>> + qmp_block_dirty_bitmap_remove(bs->node_name, name, &err);
>> + if (err) {
>> + /* Save name for proper error reporting */
>> + bitmap = name;
>> + break;
>> + }
>> + }
>> + op = "remove-all";
>> + break;
>> + }
>> case BITMAP_CLEAR:
>> qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
>> op = "clear";
> Kevin
The rest is clear.
Thank you for the review,
Den
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-05-20 23:29 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-24 10:59 [PATCH v3 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap' Denis V. Lunev via qemu development
2026-05-11 21:53 ` Denis V. Lunev
2026-05-15 13:55 ` Kevin Wolf
2026-05-20 23:28 ` Denis V. Lunev
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.