mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
qemu-img: add sub-command --remove-all to 'qemu-img bitmap'
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.
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Hanna Czenczek <hreitz@redhat.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Message-ID: <20260520235952.500250-1-den@openvz.org>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
committed by
Kevin Wolf
parent
aeea0c2804
commit
7e8cc6c886
@@ -301,15 +301,19 @@ Command description:
|
|||||||
For write tests, by default a buffer filled with zeros is written. This can be
|
For write tests, by default a buffer filled with zeros is written. This can be
|
||||||
overridden with a pattern byte specified by *PATTERN*.
|
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*
|
Perform one or more modifications of persistent bitmaps in the disk
|
||||||
in the disk image *FILENAME*. The various modifications are:
|
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.
|
``--add`` to create *BITMAP*, enabled to record future edits.
|
||||||
|
|
||||||
``--remove`` to remove *BITMAP*.
|
``--remove`` to remove *BITMAP*.
|
||||||
|
|
||||||
|
``--remove-all`` to remove all bitmaps.
|
||||||
|
|
||||||
``--clear`` to clear *BITMAP*.
|
``--clear`` to clear *BITMAP*.
|
||||||
|
|
||||||
``--enable`` to change *BITMAP* to start recording future edits.
|
``--enable`` to change *BITMAP* to start recording future edits.
|
||||||
|
|||||||
55
qemu-img.c
55
qemu-img.c
@@ -87,6 +87,7 @@ enum {
|
|||||||
OPTION_FORCE = 276,
|
OPTION_FORCE = 276,
|
||||||
OPTION_SKIP_BROKEN = 277,
|
OPTION_SKIP_BROKEN = 277,
|
||||||
OPTION_LIMITS = 278,
|
OPTION_LIMITS = 278,
|
||||||
|
OPTION_REMOVE_ALL = 279,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum OutputFormat {
|
typedef enum OutputFormat {
|
||||||
@@ -5018,6 +5019,7 @@ enum ImgBitmapAct {
|
|||||||
BITMAP_ENABLE,
|
BITMAP_ENABLE,
|
||||||
BITMAP_DISABLE,
|
BITMAP_DISABLE,
|
||||||
BITMAP_MERGE,
|
BITMAP_MERGE,
|
||||||
|
BITMAP_REMOVE_ALL,
|
||||||
};
|
};
|
||||||
typedef struct ImgBitmapAction {
|
typedef struct ImgBitmapAction {
|
||||||
enum ImgBitmapAct act;
|
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;
|
BlockDriverState *bs = NULL, *src_bs = NULL;
|
||||||
bool image_opts = false;
|
bool image_opts = false;
|
||||||
int64_t granularity = 0;
|
int64_t granularity = 0;
|
||||||
bool add = false, merge = false;
|
bool add = false, merge = false, need_bitmap_name = false;
|
||||||
QSIMPLEQ_HEAD(, ImgBitmapAction) actions;
|
QSIMPLEQ_HEAD(, ImgBitmapAction) actions;
|
||||||
ImgBitmapAction *act, *act_next;
|
ImgBitmapAction *act, *act_next;
|
||||||
const char *op;
|
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},
|
{"add", no_argument, 0, OPTION_ADD},
|
||||||
{"granularity", required_argument, 0, 'g'},
|
{"granularity", required_argument, 0, 'g'},
|
||||||
{"remove", no_argument, 0, OPTION_REMOVE},
|
{"remove", no_argument, 0, OPTION_REMOVE},
|
||||||
|
{"remove-all", no_argument, 0, OPTION_REMOVE_ALL},
|
||||||
{"clear", no_argument, 0, OPTION_CLEAR},
|
{"clear", no_argument, 0, OPTION_CLEAR},
|
||||||
{"enable", no_argument, 0, OPTION_ENABLE},
|
{"enable", no_argument, 0, OPTION_ENABLE},
|
||||||
{"disable", no_argument, 0, OPTION_DISABLE},
|
{"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) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
cmd_help(ccmd, "[-f FMT | --image-opts]\n"
|
cmd_help(ccmd, "[-f FMT | --image-opts]\n"
|
||||||
" ( --add [-g SIZE] | --remove | --clear | --enable | --disable |\n"
|
" ( --add [-g SIZE] | --remove | --remove-all | --clear | --enable |\n"
|
||||||
" --merge SOURCE [-b SRC_FILE [-F SRC_FMT]] )..\n"
|
" --disable | --merge SOURCE [-b SRC_FILE [-F SRC_FMT]] )..\n"
|
||||||
" [--object OBJDEF] FILE BITMAP\n"
|
" [--object OBJDEF] FILE [BITMAP]\n"
|
||||||
,
|
,
|
||||||
" -f, --format FMT\n"
|
" -f, --format FMT\n"
|
||||||
" specify FILE format explicitly (default: probing is used)\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"
|
" with optional multiplier suffix (in powers of 1024)\n"
|
||||||
" --remove\n"
|
" --remove\n"
|
||||||
" removes BITMAP from FILE\n"
|
" removes BITMAP from FILE\n"
|
||||||
|
" --remove-all\n"
|
||||||
|
" removes all bitmaps from FILE\n"
|
||||||
" --clear\n"
|
" --clear\n"
|
||||||
" clears BITMAP in FILE\n"
|
" clears BITMAP in FILE\n"
|
||||||
" --enable, --disable\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;
|
act->act = BITMAP_ADD;
|
||||||
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
||||||
add = true;
|
add = true;
|
||||||
|
need_bitmap_name = true;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
granularity = cvtnum("granularity", optarg, true);
|
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 = g_new0(ImgBitmapAction, 1);
|
||||||
act->act = BITMAP_REMOVE;
|
act->act = BITMAP_REMOVE;
|
||||||
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
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;
|
break;
|
||||||
case OPTION_CLEAR:
|
case OPTION_CLEAR:
|
||||||
act = g_new0(ImgBitmapAction, 1);
|
act = g_new0(ImgBitmapAction, 1);
|
||||||
act->act = BITMAP_CLEAR;
|
act->act = BITMAP_CLEAR;
|
||||||
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
||||||
|
need_bitmap_name = true;
|
||||||
break;
|
break;
|
||||||
case OPTION_ENABLE:
|
case OPTION_ENABLE:
|
||||||
act = g_new0(ImgBitmapAction, 1);
|
act = g_new0(ImgBitmapAction, 1);
|
||||||
act->act = BITMAP_ENABLE;
|
act->act = BITMAP_ENABLE;
|
||||||
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
||||||
|
need_bitmap_name = true;
|
||||||
break;
|
break;
|
||||||
case OPTION_DISABLE:
|
case OPTION_DISABLE:
|
||||||
act = g_new0(ImgBitmapAction, 1);
|
act = g_new0(ImgBitmapAction, 1);
|
||||||
act->act = BITMAP_DISABLE;
|
act->act = BITMAP_DISABLE;
|
||||||
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
||||||
|
need_bitmap_name = true;
|
||||||
break;
|
break;
|
||||||
case OPTION_MERGE:
|
case OPTION_MERGE:
|
||||||
act = g_new0(ImgBitmapAction, 1);
|
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;
|
act->src = optarg;
|
||||||
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
QSIMPLEQ_INSERT_TAIL(&actions, act, next);
|
||||||
merge = true;
|
merge = true;
|
||||||
|
need_bitmap_name = true;
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
src_filename = optarg;
|
src_filename = optarg;
|
||||||
@@ -5165,8 +5181,8 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (QSIMPLEQ_EMPTY(&actions)) {
|
if (QSIMPLEQ_EMPTY(&actions)) {
|
||||||
error_report("Need at least one of --add, --remove, --clear, "
|
error_report("Need at least one of --add, --remove, --remove-all, "
|
||||||
"--enable, --disable, or --merge");
|
"--clear, --enable, --disable, or --merge");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5184,11 +5200,22 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optind != argc - 2) {
|
if (need_bitmap_name && optind != argc - 2) {
|
||||||
error_report("Expecting filename and bitmap name");
|
error_report("Expecting filename and bitmap name");
|
||||||
goto out;
|
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];
|
filename = argv[optind];
|
||||||
bitmap = argv[optind + 1];
|
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);
|
qmp_block_dirty_bitmap_remove(bs->node_name, bitmap, &err);
|
||||||
op = "remove";
|
op = "remove";
|
||||||
break;
|
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:
|
case BITMAP_CLEAR:
|
||||||
qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
|
qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
|
||||||
op = "clear";
|
op = "clear";
|
||||||
|
|||||||
@@ -161,6 +161,30 @@ $QEMU_IMG convert --bitmaps -O qcow2 "$TEST_IMG" "$TEST_IMG.copy"
|
|||||||
TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
|
TEST_IMG="$TEST_IMG.copy" _img_info --format-specific \
|
||||||
| _filter_irrelevant_img_info
|
| _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
|
# success, all done
|
||||||
echo '*** done'
|
echo '*** done'
|
||||||
rm -f $seq.full
|
rm -f $seq.full
|
||||||
|
|||||||
@@ -180,4 +180,50 @@ Format specific information:
|
|||||||
name: b2
|
name: b2
|
||||||
granularity: 65536
|
granularity: 65536
|
||||||
corrupt: false
|
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
|
*** done
|
||||||
|
|||||||
Reference in New Issue
Block a user