qemu-img: Add --target-is-zero to convert

In many cases the target of a convert operation is a newly provisioned
target that the user knows is blank (reads as zero). In this situation
there is no requirement for qemu-img to wastefully zero out the entire
device.

Add a new option, --target-is-zero, allowing the user to indicate that
an existing target device will return zeros for all reads.

Signed-off-by: David Edmondson <david.edmondson@oracle.com>
Message-Id: <20200205110248.2009589-2-david.edmondson@oracle.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
David Edmondson 2020-02-05 11:02:48 +00:00 committed by Max Reitz
parent facda5443f
commit 168468fe19
3 changed files with 33 additions and 6 deletions

View File

@ -214,6 +214,13 @@ Parameters to convert subcommand:
will still be printed. Areas that cannot be read from the source will be will still be printed. Areas that cannot be read from the source will be
treated as containing only zeroes. treated as containing only zeroes.
.. option:: --target-is-zero
Assume that reading the destination image will always return
zeros. This parameter is mutually exclusive with a destination image
that has a backing file. It is required to also use the ``-n``
parameter to skip image creation.
Parameters to dd subcommand: Parameters to dd subcommand:
.. program:: qemu-img-dd .. program:: qemu-img-dd
@ -366,7 +373,7 @@ Command description:
4 4
Error on reading data Error on reading data
.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME .. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM* Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM*
to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can

View File

@ -39,9 +39,9 @@ SRST
ERST ERST
DEF("convert", img_convert, DEF("convert", img_convert,
"convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
SRST SRST
.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME .. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
ERST ERST
DEF("create", img_create, DEF("create", img_create,

View File

@ -70,6 +70,7 @@ enum {
OPTION_PREALLOCATION = 265, OPTION_PREALLOCATION = 265,
OPTION_SHRINK = 266, OPTION_SHRINK = 266,
OPTION_SALVAGE = 267, OPTION_SALVAGE = 267,
OPTION_TARGET_IS_ZERO = 268,
}; };
typedef enum OutputFormat { typedef enum OutputFormat {
@ -1984,10 +1985,9 @@ static int convert_do_copy(ImgConvertState *s)
int64_t sector_num = 0; int64_t sector_num = 0;
/* Check whether we have zero initialisation or can get it efficiently */ /* Check whether we have zero initialisation or can get it efficiently */
if (s->target_is_new && s->min_sparse && !s->target_has_backing) { if (!s->has_zero_init && s->target_is_new && s->min_sparse &&
!s->target_has_backing) {
s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target)); s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
} else {
s->has_zero_init = false;
} }
if (!s->has_zero_init && !s->target_has_backing && if (!s->has_zero_init && !s->target_has_backing &&
@ -2086,6 +2086,7 @@ static int img_convert(int argc, char **argv)
{"force-share", no_argument, 0, 'U'}, {"force-share", no_argument, 0, 'U'},
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS}, {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
{"salvage", no_argument, 0, OPTION_SALVAGE}, {"salvage", no_argument, 0, OPTION_SALVAGE},
{"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU", c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
@ -2209,6 +2210,14 @@ static int img_convert(int argc, char **argv)
case OPTION_TARGET_IMAGE_OPTS: case OPTION_TARGET_IMAGE_OPTS:
tgt_image_opts = true; tgt_image_opts = true;
break; break;
case OPTION_TARGET_IS_ZERO:
/*
* The user asserting that the target is blank has the
* same effect as the target driver supporting zero
* initialisation.
*/
s.has_zero_init = true;
break;
} }
} }
@ -2247,6 +2256,11 @@ static int img_convert(int argc, char **argv)
warn_report("This will become an error in future QEMU versions."); warn_report("This will become an error in future QEMU versions.");
} }
if (s.has_zero_init && !skip_create) {
error_report("--target-is-zero requires use of -n flag");
goto fail_getopt;
}
s.src_num = argc - optind - 1; s.src_num = argc - optind - 1;
out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL; out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
@ -2380,6 +2394,12 @@ static int img_convert(int argc, char **argv)
} }
s.target_has_backing = (bool) out_baseimg; s.target_has_backing = (bool) out_baseimg;
if (s.has_zero_init && s.target_has_backing) {
error_report("Cannot use --target-is-zero when the destination "
"image has a backing file");
goto out;
}
if (s.src_num > 1 && out_baseimg) { if (s.src_num > 1 && out_baseimg) {
error_report("Having a backing file for the target makes no sense when " error_report("Having a backing file for the target makes no sense when "
"concatenating multiple input images"); "concatenating multiple input images");