* [PATCH v4 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
@ 2026-05-20 23:59 Denis V. Lunev via qemu development
2026-05-28 9:25 ` Denis V. Lunev
2026-05-29 14:16 ` Kevin Wolf
0 siblings, 2 replies; 3+ messages in thread
From: Denis V. Lunev via qemu development @ 2026-05-20 23:59 UTC (permalink / raw)
To: qemu-devel; +Cc: den, 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'. The
new sub-command also composes with other bitmap actions in the same
invocation, so a common "wipe and recreate" workflow can be expressed
as
qemu-img bitmap --remove-all --add NEW FILE
instead of enumerating existing bitmaps, removing them one by one,
and only then adding the fresh one.
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Kevin Wolf <kwolf@redhat.com>
CC: Hanna Reitz <hreitz@redhat.com>
---
Changes from v3:
* renamed 'any' to 'need_bitmap_name' for clarity (Kevin)
* dropped the redundant 'remove_all' flag; an empty actions list is
already caught earlier, so '!need_bitmap_name' alone is sufficient
to detect the --remove-all-only case (Kevin)
* one assignment per line for the action flags (Kevin)
* simplified the BITMAP_REMOVE_ALL loop to the inline-assignment
while ((bm = bdrv_dirty_bitmap_first(bs))) form (Kevin)
* corrected the inline --help synopsis to show FILE [BITMAP], matching
the .rst
* rewrote the parser-side comment to spell out the invariant and to
call out that '--remove-all --add foo' is a supported composition
* expanded the commit message to motivate the wipe-and-recreate flow
* added iotest coverage in tests/qemu-iotests/tests/qemu-img-bitmaps
for the basic sweep and the --remove-all --add composition
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 | 55 ++++++++++++++++---
tests/qemu-iotests/tests/qemu-img-bitmaps | 24 ++++++++
tests/qemu-iotests/tests/qemu-img-bitmaps.out | 46 ++++++++++++++++
4 files changed, 125 insertions(+), 10 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..2f63d31141 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, need_bitmap_name = 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,9 +5073,9 @@ 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"
-" [--object OBJDEF] FILE BITMAP\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"
" specify FILE format explicitly (default: probing is used)\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"
@@ -5116,6 +5121,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
act->act = BITMAP_ADD;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
add = true;
+ need_bitmap_name = true;
break;
case 'g':
granularity = cvtnum("granularity", optarg, true);
@@ -5127,21 +5133,30 @@ 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);
+ need_bitmap_name = true;
+ break;
+ case OPTION_REMOVE_ALL:
+ act = g_new0(ImgBitmapAction, 1);
+ act->act = BITMAP_REMOVE_ALL;
+ QSIMPLEQ_INSERT_TAIL(&actions, act, next);
break;
case OPTION_CLEAR:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_CLEAR;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ need_bitmap_name = true;
break;
case OPTION_ENABLE:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_ENABLE;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ need_bitmap_name = true;
break;
case OPTION_DISABLE:
act = g_new0(ImgBitmapAction, 1);
act->act = BITMAP_DISABLE;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
+ need_bitmap_name = true;
break;
case OPTION_MERGE:
act = g_new0(ImgBitmapAction, 1);
@@ -5149,6 +5164,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
act->src = optarg;
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
merge = true;
+ need_bitmap_name = true;
break;
case 'b':
src_filename = optarg;
@@ -5165,8 +5181,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,11 +5200,22 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
goto out;
}
- if (optind != argc - 2) {
+ if (need_bitmap_name && optind != argc - 2) {
error_report("Expecting filename and bitmap name");
goto out;
}
+ /*
+ * Every action other than --remove-all sets need_bitmap_name, so
+ * !need_bitmap_name means the only action(s) given were --remove-all
+ * and the BITMAP positional argument must be omitted. Combinations
+ * like '--remove-all --add foo' remain valid via the branch above.
+ */
+ if (!need_bitmap_name && optind != argc - 1) {
+ error_report("Expecting filename");
+ goto out;
+ }
+
filename = argv[optind];
bitmap = argv[optind + 1];
@@ -5225,6 +5252,20 @@ 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: {
+ BdrvDirtyBitmap *bm;
+ while ((bm = bdrv_dirty_bitmap_first(bs))) {
+ const char *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";
diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps b/tests/qemu-iotests/tests/qemu-img-bitmaps
index 7a3fe8c3d3..979bc0d6c9 100755
--- a/tests/qemu-iotests/tests/qemu-img-bitmaps
+++ b/tests/qemu-iotests/tests/qemu-img-bitmaps
@@ -161,6 +161,30 @@ $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy"
TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
| _filter_irrelevant_img_info
+echo
+echo "=== Check --remove-all ==="
+echo
+
+# Start from a fresh image so prior state does not bleed into the assertions
+_rm_test_img "$TEST_IMG"
+_make_test_img 10M
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b0
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b1
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b2
+_img_info --format-specific | _filter_irrelevant_img_info
+
+# Sweep every bitmap in a single command, no BITMAP positional
+echo
+$QEMU_IMG bitmap --remove-all -f $IMGFMT "$TEST_IMG"
+_img_info --format-specific | _filter_irrelevant_img_info
+
+# Wipe + recreate in one invocation: only 'fresh' should remain
+echo
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b0
+$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b1
+$QEMU_IMG bitmap --remove-all --add -f $IMGFMT "$TEST_IMG" fresh
+_img_info --format-specific | _filter_irrelevant_img_info
+
# success, all done
echo '*** done'
rm -f $seq.full
diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
index 74b81f703b..99290d3ba5 100644
--- a/tests/qemu-iotests/tests/qemu-img-bitmaps.out
+++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
@@ -180,4 +180,50 @@ Format specific information:
name: b2
granularity: 65536
corrupt: false
+
+=== Check --remove-all ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 10 MiB (10485760 bytes)
+cluster_size: 65536
+Format specific information:
+ bitmaps:
+ [0]:
+ flags:
+ [0]: auto
+ name: b0
+ granularity: 65536
+ [1]:
+ flags:
+ [0]: auto
+ name: b1
+ granularity: 65536
+ [2]:
+ flags:
+ [0]: auto
+ name: b2
+ granularity: 65536
+ corrupt: false
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 10 MiB (10485760 bytes)
+cluster_size: 65536
+Format specific information:
+ corrupt: false
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 10 MiB (10485760 bytes)
+cluster_size: 65536
+Format specific information:
+ bitmaps:
+ [0]:
+ flags:
+ [0]: auto
+ name: fresh
+ granularity: 65536
+ corrupt: false
*** done
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH v4 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
2026-05-20 23:59 [PATCH v4 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap' Denis V. Lunev via qemu development
@ 2026-05-28 9:25 ` Denis V. Lunev
2026-05-29 14:16 ` Kevin Wolf
1 sibling, 0 replies; 3+ messages in thread
From: Denis V. Lunev @ 2026-05-28 9:25 UTC (permalink / raw)
To: Denis V. Lunev, qemu-devel; +Cc: Kevin Wolf, Hanna Reitz
On 5/21/26 01: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'. The
> new sub-command also composes with other bitmap actions in the same
> invocation, so a common "wipe and recreate" workflow can be expressed
> as
> qemu-img bitmap --remove-all --add NEW FILE
> instead of enumerating existing bitmaps, removing them one by one,
> and only then adding the fresh one.
>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Hanna Reitz <hreitz@redhat.com>
> ---
> Changes from v3:
> * renamed 'any' to 'need_bitmap_name' for clarity (Kevin)
> * dropped the redundant 'remove_all' flag; an empty actions list is
> already caught earlier, so '!need_bitmap_name' alone is sufficient
> to detect the --remove-all-only case (Kevin)
> * one assignment per line for the action flags (Kevin)
> * simplified the BITMAP_REMOVE_ALL loop to the inline-assignment
> while ((bm = bdrv_dirty_bitmap_first(bs))) form (Kevin)
> * corrected the inline --help synopsis to show FILE [BITMAP], matching
> the .rst
> * rewrote the parser-side comment to spell out the invariant and to
> call out that '--remove-all --add foo' is a supported composition
> * expanded the commit message to motivate the wipe-and-recreate flow
> * added iotest coverage in tests/qemu-iotests/tests/qemu-img-bitmaps
> for the basic sweep and the --remove-all --add composition
>
> 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 | 55 ++++++++++++++++---
> tests/qemu-iotests/tests/qemu-img-bitmaps | 24 ++++++++
> tests/qemu-iotests/tests/qemu-img-bitmaps.out | 46 ++++++++++++++++
> 4 files changed, 125 insertions(+), 10 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..2f63d31141 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, need_bitmap_name = 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,9 +5073,9 @@ 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"
> -" [--object OBJDEF] FILE BITMAP\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"
> " specify FILE format explicitly (default: probing is used)\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"
> @@ -5116,6 +5121,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
> act->act = BITMAP_ADD;
> QSIMPLEQ_INSERT_TAIL(&actions, act, next);
> add = true;
> + need_bitmap_name = true;
> break;
> case 'g':
> granularity = cvtnum("granularity", optarg, true);
> @@ -5127,21 +5133,30 @@ 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);
> + need_bitmap_name = true;
> + break;
> + case OPTION_REMOVE_ALL:
> + act = g_new0(ImgBitmapAction, 1);
> + act->act = BITMAP_REMOVE_ALL;
> + QSIMPLEQ_INSERT_TAIL(&actions, act, next);
> break;
> case OPTION_CLEAR:
> act = g_new0(ImgBitmapAction, 1);
> act->act = BITMAP_CLEAR;
> QSIMPLEQ_INSERT_TAIL(&actions, act, next);
> + need_bitmap_name = true;
> break;
> case OPTION_ENABLE:
> act = g_new0(ImgBitmapAction, 1);
> act->act = BITMAP_ENABLE;
> QSIMPLEQ_INSERT_TAIL(&actions, act, next);
> + need_bitmap_name = true;
> break;
> case OPTION_DISABLE:
> act = g_new0(ImgBitmapAction, 1);
> act->act = BITMAP_DISABLE;
> QSIMPLEQ_INSERT_TAIL(&actions, act, next);
> + need_bitmap_name = true;
> break;
> case OPTION_MERGE:
> act = g_new0(ImgBitmapAction, 1);
> @@ -5149,6 +5164,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
> act->src = optarg;
> QSIMPLEQ_INSERT_TAIL(&actions, act, next);
> merge = true;
> + need_bitmap_name = true;
> break;
> case 'b':
> src_filename = optarg;
> @@ -5165,8 +5181,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,11 +5200,22 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
> goto out;
> }
>
> - if (optind != argc - 2) {
> + if (need_bitmap_name && optind != argc - 2) {
> error_report("Expecting filename and bitmap name");
> goto out;
> }
>
> + /*
> + * Every action other than --remove-all sets need_bitmap_name, so
> + * !need_bitmap_name means the only action(s) given were --remove-all
> + * and the BITMAP positional argument must be omitted. Combinations
> + * like '--remove-all --add foo' remain valid via the branch above.
> + */
> + if (!need_bitmap_name && optind != argc - 1) {
> + error_report("Expecting filename");
> + goto out;
> + }
> +
> filename = argv[optind];
> bitmap = argv[optind + 1];
>
> @@ -5225,6 +5252,20 @@ 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: {
> + BdrvDirtyBitmap *bm;
> + while ((bm = bdrv_dirty_bitmap_first(bs))) {
> + const char *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";
> diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps b/tests/qemu-iotests/tests/qemu-img-bitmaps
> index 7a3fe8c3d3..979bc0d6c9 100755
> --- a/tests/qemu-iotests/tests/qemu-img-bitmaps
> +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps
> @@ -161,6 +161,30 @@ $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy"
> TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
> | _filter_irrelevant_img_info
>
> +echo
> +echo "=== Check --remove-all ==="
> +echo
> +
> +# Start from a fresh image so prior state does not bleed into the assertions
> +_rm_test_img "$TEST_IMG"
> +_make_test_img 10M
> +$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b0
> +$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b1
> +$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b2
> +_img_info --format-specific | _filter_irrelevant_img_info
> +
> +# Sweep every bitmap in a single command, no BITMAP positional
> +echo
> +$QEMU_IMG bitmap --remove-all -f $IMGFMT "$TEST_IMG"
> +_img_info --format-specific | _filter_irrelevant_img_info
> +
> +# Wipe + recreate in one invocation: only 'fresh' should remain
> +echo
> +$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b0
> +$QEMU_IMG bitmap --add -f $IMGFMT "$TEST_IMG" b1
> +$QEMU_IMG bitmap --remove-all --add -f $IMGFMT "$TEST_IMG" fresh
> +_img_info --format-specific | _filter_irrelevant_img_info
> +
> # success, all done
> echo '*** done'
> rm -f $seq.full
> diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
> index 74b81f703b..99290d3ba5 100644
> --- a/tests/qemu-iotests/tests/qemu-img-bitmaps.out
> +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
> @@ -180,4 +180,50 @@ Format specific information:
> name: b2
> granularity: 65536
> corrupt: false
> +
> +=== Check --remove-all ===
> +
> +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
> +image: TEST_DIR/t.IMGFMT
> +file format: IMGFMT
> +virtual size: 10 MiB (10485760 bytes)
> +cluster_size: 65536
> +Format specific information:
> + bitmaps:
> + [0]:
> + flags:
> + [0]: auto
> + name: b0
> + granularity: 65536
> + [1]:
> + flags:
> + [0]: auto
> + name: b1
> + granularity: 65536
> + [2]:
> + flags:
> + [0]: auto
> + name: b2
> + granularity: 65536
> + corrupt: false
> +
> +image: TEST_DIR/t.IMGFMT
> +file format: IMGFMT
> +virtual size: 10 MiB (10485760 bytes)
> +cluster_size: 65536
> +Format specific information:
> + corrupt: false
> +
> +image: TEST_DIR/t.IMGFMT
> +file format: IMGFMT
> +virtual size: 10 MiB (10485760 bytes)
> +cluster_size: 65536
> +Format specific information:
> + bitmaps:
> + [0]:
> + flags:
> + [0]: auto
> + name: fresh
> + granularity: 65536
> + corrupt: false
> *** done
ping
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH v4 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
2026-05-20 23:59 [PATCH v4 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap' Denis V. Lunev via qemu development
2026-05-28 9:25 ` Denis V. Lunev
@ 2026-05-29 14:16 ` Kevin Wolf
1 sibling, 0 replies; 3+ messages in thread
From: Kevin Wolf @ 2026-05-29 14:16 UTC (permalink / raw)
To: Denis V. Lunev; +Cc: qemu-devel, Hanna Reitz
Am 21.05.2026 um 01: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'. The
> new sub-command also composes with other bitmap actions in the same
> invocation, so a common "wipe and recreate" workflow can be expressed
> as
> qemu-img bitmap --remove-all --add NEW FILE
> instead of enumerating existing bitmaps, removing them one by one,
> and only then adding the fresh one.
>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> CC: Kevin Wolf <kwolf@redhat.com>
> CC: Hanna Reitz <hreitz@redhat.com>
Thanks, applied to the block branch.
Kevin
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-29 14:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-20 23:59 [PATCH v4 1/1] qemu-img: add sub-command --remove-all to 'qemu-img bitmap' Denis V. Lunev via qemu development
2026-05-28 9:25 ` Denis V. Lunev
2026-05-29 14:16 ` Kevin Wolf
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.