21.05.2020 22:21, Eric Blake wrote:
Make it easier to copy all the persistent bitmaps of (the top layer
of) a source image along with its guest-visible contents, by adding a
boolean flag for use with qemu-img convert. This is basically
shorthand, as the same effect could be accomplished with a series of
'qemu-img bitmap --add' and 'qemu-img bitmap --merge -b source'
commands, or by their corresponding QMP commands.
Note that this command will fail in the same scenarios where 'qemu-img
measure' omits a 'bitmaps size:' line, namely, when either the source
or the destination lacks persistent bitmap support altogether.
See also https://bugzilla.redhat.com/show_bug.cgi?id=1779893
While touching this, clean up a couple coding issues spotted in the
same function: an extra blank line, and merging back-to-back 'if
(!skip_create)' blocks.
Signed-off-by: Eric Blake <ebl...@redhat.com>
---
[..]
diff --git a/qemu-img.c b/qemu-img.c
index 0778d8f56614..8ecebe178890 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -78,6 +78,7 @@ enum {
OPTION_ENABLE = 272,
OPTION_DISABLE = 273,
OPTION_MERGE = 274,
[..]
static int img_convert(int argc, char **argv)
@@ -2160,6 +2195,8 @@ static int img_convert(int argc, char **argv)
int64_t ret = -EINVAL;
bool force_share = false;
bool explict_min_sparse = false;
+ bool bitmaps = false;
+ size_t nbitmaps = 0;
ImgConvertState s = (ImgConvertState) {
/* Need at least 4k of zeros for sparse detection */
@@ -2179,6 +2216,7 @@ static int img_convert(int argc, char **argv)
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
{"salvage", no_argument, 0, OPTION_SALVAGE},
{"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
+ {"bitmaps", no_argument, 0, OPTION_BITMAPS},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
@@ -2304,6 +2342,9 @@ static int img_convert(int argc, char **argv)
*/
s.has_zero_init = true;
break;
+ case OPTION_BITMAPS:
+ bitmaps = true;
+ break;
}
}
@@ -2365,7 +2406,6 @@ static int img_convert(int argc, char **argv)
goto fail_getopt;
}
-
/* ret is still -EINVAL until here */
ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
if (ret < 0) {
@@ -2525,6 +2565,27 @@ static int img_convert(int argc, char **argv)
}
}
+ /* Determine how many bitmaps need copying */
+ if (bitmaps) {
+ BdrvDirtyBitmap *bm;
+
+ if (s.src_num > 1) {
+ error_report("Copying bitmaps only possible with single source");
+ ret = -1;
+ goto out;
+ }
+ if (!bdrv_supports_persistent_dirty_bitmap(blk_bs(s.src[0]))) {
+ error_report("Source lacks bitmap support");
+ ret = -1;
+ goto out;
+ }
+ FOR_EACH_DIRTY_BITMAP(blk_bs(s.src[0]), bm) {
+ if (bdrv_dirty_bitmap_get_persistence(bm)) {
+ nbitmaps++;
+ }
+ }
+ }
+
/*
* The later open call will need any decryption secrets, and
* bdrv_create() will purge "opts", so extract them now before
@@ -2533,9 +2594,7 @@ static int img_convert(int argc, char **argv)
if (!skip_create) {
open_opts = qdict_new();
qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort);
- }
- if (!skip_create) {
/* Create the new image */
ret = bdrv_create(drv, out_filename, opts, &local_err);
if (ret < 0) {
@@ -2573,6 +2632,13 @@ static int img_convert(int argc, char **argv)
}
out_bs = blk_bs(s.target);
+ if (nbitmaps > 0 && !bdrv_supports_persistent_dirty_bitmap(out_bs)) {
We will not fail, if target doesn't support bitmaps, source supports them but
has no bitmaps? Doesn't seem to be a problem, but a bit less strict than you
write in commit message.
So, maybe, s/nbitmaps > 0/bitmaps/
+ error_report("Format driver '%s' does not support bitmaps",
+ out_fmt);
Hmm seems, out_fmt may be NULL at this point, consider the path:
const char *out_fmt = NULL
...
[no -O option]
--target-image-opts, so out_fmt doesn't default to "raw" but remains NULL
...
So, with s/out_fmt/out_bs->drv->format_name/ (and with or without s/nbitmaps >
0/bitmaps/):
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com>
--
Best regards,
Vladimir