mirror of https://gitee.com/openkylin/qemu.git
qemu-img: simplify img_convert
img_convert has been around before there was an ImgConvertState or a block backend, but it has never been modified to directly use these structs. Change this by parsing parameters directly into the ImgConvertState and directly use BlockBackend where possible. Furthermore variable initialization has been reworked and sorted. Signed-off-by: Peter Lieven <pl@kamp.de> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
362b3786eb
commit
9fd77f9972
217
qemu-img.c
217
qemu-img.c
|
@ -1522,7 +1522,7 @@ typedef struct ImgConvertState {
|
||||||
int min_sparse;
|
int min_sparse;
|
||||||
size_t cluster_sectors;
|
size_t cluster_sectors;
|
||||||
size_t buf_sectors;
|
size_t buf_sectors;
|
||||||
int num_coroutines;
|
long num_coroutines;
|
||||||
int running_coroutines;
|
int running_coroutines;
|
||||||
Coroutine *co[MAX_COROUTINES];
|
Coroutine *co[MAX_COROUTINES];
|
||||||
int64_t wait_sector_num[MAX_COROUTINES];
|
int64_t wait_sector_num[MAX_COROUTINES];
|
||||||
|
@ -1916,39 +1916,29 @@ static int convert_do_copy(ImgConvertState *s)
|
||||||
|
|
||||||
static int img_convert(int argc, char **argv)
|
static int img_convert(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int c, bs_n, bs_i, compress, cluster_sectors, skip_create;
|
int c, bs_i, flags, src_flags = 0;
|
||||||
int64_t ret = 0;
|
const char *fmt = NULL, *out_fmt = "raw", *cache = "unsafe",
|
||||||
int progress = 0, flags, src_flags;
|
*src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
|
||||||
bool writethrough, src_writethrough;
|
*out_filename, *out_baseimg_param, *snapshot_name = NULL;
|
||||||
const char *fmt, *out_fmt, *cache, *src_cache, *out_baseimg, *out_filename;
|
|
||||||
BlockDriver *drv, *proto_drv;
|
BlockDriver *drv, *proto_drv;
|
||||||
BlockBackend **blk = NULL, *out_blk = NULL;
|
|
||||||
BlockDriverState **bs = NULL, *out_bs = NULL;
|
|
||||||
int64_t total_sectors;
|
|
||||||
int64_t *bs_sectors = NULL;
|
|
||||||
size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE;
|
|
||||||
BlockDriverInfo bdi;
|
BlockDriverInfo bdi;
|
||||||
QemuOpts *opts = NULL;
|
BlockDriverState *out_bs;
|
||||||
|
QemuOpts *opts = NULL, *sn_opts = NULL;
|
||||||
QemuOptsList *create_opts = NULL;
|
QemuOptsList *create_opts = NULL;
|
||||||
const char *out_baseimg_param;
|
|
||||||
char *options = NULL;
|
char *options = NULL;
|
||||||
const char *snapshot_name = NULL;
|
|
||||||
int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
|
|
||||||
bool quiet = false;
|
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
QemuOpts *sn_opts = NULL;
|
bool writethrough, src_writethrough, quiet = false, image_opts = false,
|
||||||
ImgConvertState state;
|
skip_create = false, progress = false;
|
||||||
bool image_opts = false;
|
int64_t ret = -EINVAL;
|
||||||
bool wr_in_order = true;
|
|
||||||
long num_coroutines = 8;
|
ImgConvertState s = (ImgConvertState) {
|
||||||
|
/* Need at least 4k of zeros for sparse detection */
|
||||||
|
.min_sparse = 8,
|
||||||
|
.buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE,
|
||||||
|
.wr_in_order = true,
|
||||||
|
.num_coroutines = 8,
|
||||||
|
};
|
||||||
|
|
||||||
fmt = NULL;
|
|
||||||
out_fmt = "raw";
|
|
||||||
cache = "unsafe";
|
|
||||||
src_cache = BDRV_DEFAULT_CACHE;
|
|
||||||
out_baseimg = NULL;
|
|
||||||
compress = 0;
|
|
||||||
skip_create = 0;
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
|
@ -1981,22 +1971,19 @@ static int img_convert(int argc, char **argv)
|
||||||
out_baseimg = optarg;
|
out_baseimg = optarg;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
compress = 1;
|
s.compressed = true;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
error_report("option -e is deprecated, please use \'-o "
|
error_report("option -e is deprecated, please use \'-o "
|
||||||
"encryption\' instead!");
|
"encryption\' instead!");
|
||||||
ret = -1;
|
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
case '6':
|
case '6':
|
||||||
error_report("option -6 is deprecated, please use \'-o "
|
error_report("option -6 is deprecated, please use \'-o "
|
||||||
"compat6\' instead!");
|
"compat6\' instead!");
|
||||||
ret = -1;
|
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
case 'o':
|
case 'o':
|
||||||
if (!is_valid_option_list(optarg)) {
|
if (!is_valid_option_list(optarg)) {
|
||||||
error_report("Invalid option list: %s", optarg);
|
error_report("Invalid option list: %s", optarg);
|
||||||
ret = -1;
|
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
}
|
}
|
||||||
if (!options) {
|
if (!options) {
|
||||||
|
@ -2017,7 +2004,6 @@ static int img_convert(int argc, char **argv)
|
||||||
if (!sn_opts) {
|
if (!sn_opts) {
|
||||||
error_report("Failed in parsing snapshot param '%s'",
|
error_report("Failed in parsing snapshot param '%s'",
|
||||||
optarg);
|
optarg);
|
||||||
ret = -1;
|
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2031,15 +2017,14 @@ static int img_convert(int argc, char **argv)
|
||||||
sval = cvtnum(optarg);
|
sval = cvtnum(optarg);
|
||||||
if (sval < 0) {
|
if (sval < 0) {
|
||||||
error_report("Invalid minimum zero buffer size for sparse output specified");
|
error_report("Invalid minimum zero buffer size for sparse output specified");
|
||||||
ret = -1;
|
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
min_sparse = sval / BDRV_SECTOR_SIZE;
|
s.min_sparse = sval / BDRV_SECTOR_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p':
|
case 'p':
|
||||||
progress = 1;
|
progress = true;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
cache = optarg;
|
cache = optarg;
|
||||||
|
@ -2051,19 +2036,18 @@ static int img_convert(int argc, char **argv)
|
||||||
quiet = true;
|
quiet = true;
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
skip_create = 1;
|
skip_create = true;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if (qemu_strtol(optarg, NULL, 0, &num_coroutines) ||
|
if (qemu_strtol(optarg, NULL, 0, &s.num_coroutines) ||
|
||||||
num_coroutines < 1 || num_coroutines > MAX_COROUTINES) {
|
s.num_coroutines < 1 || s.num_coroutines > MAX_COROUTINES) {
|
||||||
error_report("Invalid number of coroutines. Allowed number of"
|
error_report("Invalid number of coroutines. Allowed number of"
|
||||||
" coroutines is between 1 and %d", MAX_COROUTINES);
|
" coroutines is between 1 and %d", MAX_COROUTINES);
|
||||||
ret = -1;
|
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'W':
|
case 'W':
|
||||||
wr_in_order = false;
|
s.wr_in_order = false;
|
||||||
break;
|
break;
|
||||||
case OPTION_OBJECT:
|
case OPTION_OBJECT:
|
||||||
opts = qemu_opts_parse_noisily(&qemu_object_opts,
|
opts = qemu_opts_parse_noisily(&qemu_object_opts,
|
||||||
|
@ -2084,83 +2068,79 @@ static int img_convert(int argc, char **argv)
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wr_in_order && compress) {
|
if (!s.wr_in_order && s.compressed) {
|
||||||
error_report("Out of order write and compress are mutually exclusive");
|
error_report("Out of order write and compress are mutually exclusive");
|
||||||
ret = -1;
|
goto fail_getopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.src_num = argc - optind - 1;
|
||||||
|
out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
|
||||||
|
|
||||||
|
if (options && has_help_option(options)) {
|
||||||
|
ret = print_block_option_help(out_filename, out_fmt);
|
||||||
|
goto fail_getopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.src_num < 1) {
|
||||||
|
error_report("Must specify image file name");
|
||||||
|
goto fail_getopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (s.src_num > 1 && out_baseimg) {
|
||||||
|
error_report("-B makes no sense when concatenating multiple input "
|
||||||
|
"images");
|
||||||
|
goto fail_getopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ret is still -EINVAL until here */
|
||||||
|
ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_report("Invalid source cache option: %s", src_cache);
|
||||||
goto fail_getopt;
|
goto fail_getopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize before goto out */
|
/* Initialize before goto out */
|
||||||
if (quiet) {
|
if (quiet) {
|
||||||
progress = 0;
|
progress = false;
|
||||||
}
|
}
|
||||||
qemu_progress_init(progress, 1.0);
|
qemu_progress_init(progress, 1.0);
|
||||||
|
|
||||||
bs_n = argc - optind - 1;
|
|
||||||
out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;
|
|
||||||
|
|
||||||
if (options && has_help_option(options)) {
|
|
||||||
ret = print_block_option_help(out_filename, out_fmt);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bs_n < 1) {
|
|
||||||
error_exit("Must specify image file name");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (bs_n > 1 && out_baseimg) {
|
|
||||||
error_report("-B makes no sense when concatenating multiple input "
|
|
||||||
"images");
|
|
||||||
ret = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_flags = 0;
|
|
||||||
ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
|
|
||||||
if (ret < 0) {
|
|
||||||
error_report("Invalid source cache option: %s", src_cache);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_progress_print(0, 100);
|
qemu_progress_print(0, 100);
|
||||||
|
|
||||||
blk = g_new0(BlockBackend *, bs_n);
|
s.src = g_new0(BlockBackend *, s.src_num);
|
||||||
bs = g_new0(BlockDriverState *, bs_n);
|
s.src_sectors = g_new(int64_t, s.src_num);
|
||||||
bs_sectors = g_new(int64_t, bs_n);
|
|
||||||
|
|
||||||
total_sectors = 0;
|
for (bs_i = 0; bs_i < s.src_num; bs_i++) {
|
||||||
for (bs_i = 0; bs_i < bs_n; bs_i++) {
|
s.src[bs_i] = img_open(image_opts, argv[optind + bs_i],
|
||||||
blk[bs_i] = img_open(image_opts, argv[optind + bs_i],
|
|
||||||
fmt, src_flags, src_writethrough, quiet);
|
fmt, src_flags, src_writethrough, quiet);
|
||||||
if (!blk[bs_i]) {
|
if (!s.src[bs_i]) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
bs[bs_i] = blk_bs(blk[bs_i]);
|
s.src_sectors[bs_i] = blk_nb_sectors(s.src[bs_i]);
|
||||||
bs_sectors[bs_i] = blk_nb_sectors(blk[bs_i]);
|
if (s.src_sectors[bs_i] < 0) {
|
||||||
if (bs_sectors[bs_i] < 0) {
|
|
||||||
error_report("Could not get size of %s: %s",
|
error_report("Could not get size of %s: %s",
|
||||||
argv[optind + bs_i], strerror(-bs_sectors[bs_i]));
|
argv[optind + bs_i], strerror(-s.src_sectors[bs_i]));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
total_sectors += bs_sectors[bs_i];
|
s.total_sectors += s.src_sectors[bs_i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sn_opts) {
|
if (sn_opts) {
|
||||||
bdrv_snapshot_load_tmp(bs[0],
|
bdrv_snapshot_load_tmp(blk_bs(s.src[0]),
|
||||||
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
|
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
|
||||||
qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
|
qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
|
||||||
&local_err);
|
&local_err);
|
||||||
} else if (snapshot_name != NULL) {
|
} else if (snapshot_name != NULL) {
|
||||||
if (bs_n > 1) {
|
if (s.src_num > 1) {
|
||||||
error_report("No support for concatenating multiple snapshot");
|
error_report("No support for concatenating multiple snapshot");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err);
|
bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(s.src[0]), snapshot_name,
|
||||||
|
&local_err);
|
||||||
}
|
}
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_reportf_err(local_err, "Failed to load snapshot: ");
|
error_reportf_err(local_err, "Failed to load snapshot: ");
|
||||||
|
@ -2211,7 +2191,7 @@ static int img_convert(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512,
|
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s.total_sectors * 512,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);
|
ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -2224,9 +2204,10 @@ static int img_convert(int argc, char **argv)
|
||||||
if (out_baseimg_param) {
|
if (out_baseimg_param) {
|
||||||
out_baseimg = out_baseimg_param;
|
out_baseimg = out_baseimg_param;
|
||||||
}
|
}
|
||||||
|
s.target_has_backing = (bool) out_baseimg;
|
||||||
|
|
||||||
/* Check if compression is supported */
|
/* Check if compression is supported */
|
||||||
if (compress) {
|
if (s.compressed) {
|
||||||
bool encryption =
|
bool encryption =
|
||||||
qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false);
|
qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false);
|
||||||
const char *preallocation =
|
const char *preallocation =
|
||||||
|
@ -2265,7 +2246,7 @@ static int img_convert(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
|
flags = s.min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
|
||||||
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("Invalid cache option: %s", cache);
|
error_report("Invalid cache option: %s", cache);
|
||||||
|
@ -2277,64 +2258,48 @@ static int img_convert(int argc, char **argv)
|
||||||
* the bdrv_create() call which takes different params.
|
* the bdrv_create() call which takes different params.
|
||||||
* Not critical right now, so fix can wait...
|
* Not critical right now, so fix can wait...
|
||||||
*/
|
*/
|
||||||
out_blk = img_open_file(out_filename, out_fmt, flags, writethrough, quiet);
|
s.target = img_open_file(out_filename, out_fmt, flags, writethrough, quiet);
|
||||||
if (!out_blk) {
|
if (!s.target) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
out_bs = blk_bs(out_blk);
|
out_bs = blk_bs(s.target);
|
||||||
|
|
||||||
/* increase bufsectors from the default 4096 (2M) if opt_transfer
|
/* increase bufsectors from the default 4096 (2M) if opt_transfer
|
||||||
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
|
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
|
||||||
* as maximum. */
|
* as maximum. */
|
||||||
bufsectors = MIN(32768,
|
s.buf_sectors = MIN(32768,
|
||||||
MAX(bufsectors,
|
MAX(s.buf_sectors,
|
||||||
MAX(out_bs->bl.opt_transfer >> BDRV_SECTOR_BITS,
|
MAX(out_bs->bl.opt_transfer >> BDRV_SECTOR_BITS,
|
||||||
out_bs->bl.pdiscard_alignment >>
|
out_bs->bl.pdiscard_alignment >>
|
||||||
BDRV_SECTOR_BITS)));
|
BDRV_SECTOR_BITS)));
|
||||||
|
|
||||||
if (skip_create) {
|
if (skip_create) {
|
||||||
int64_t output_sectors = blk_nb_sectors(out_blk);
|
int64_t output_sectors = blk_nb_sectors(s.target);
|
||||||
if (output_sectors < 0) {
|
if (output_sectors < 0) {
|
||||||
error_report("unable to get output image length: %s",
|
error_report("unable to get output image length: %s",
|
||||||
strerror(-output_sectors));
|
strerror(-output_sectors));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
} else if (output_sectors < total_sectors) {
|
} else if (output_sectors < s.total_sectors) {
|
||||||
error_report("output file is smaller than input file");
|
error_report("output file is smaller than input file");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cluster_sectors = 0;
|
|
||||||
ret = bdrv_get_info(out_bs, &bdi);
|
ret = bdrv_get_info(out_bs, &bdi);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (compress) {
|
if (s.compressed) {
|
||||||
error_report("could not get block driver info");
|
error_report("could not get block driver info");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
compress = compress || bdi.needs_compressed_writes;
|
s.compressed = s.compressed || bdi.needs_compressed_writes;
|
||||||
cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
|
s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = (ImgConvertState) {
|
ret = convert_do_copy(&s);
|
||||||
.src = blk,
|
|
||||||
.src_sectors = bs_sectors,
|
|
||||||
.src_num = bs_n,
|
|
||||||
.total_sectors = total_sectors,
|
|
||||||
.target = out_blk,
|
|
||||||
.compressed = compress,
|
|
||||||
.target_has_backing = (bool) out_baseimg,
|
|
||||||
.min_sparse = min_sparse,
|
|
||||||
.cluster_sectors = cluster_sectors,
|
|
||||||
.buf_sectors = bufsectors,
|
|
||||||
.wr_in_order = wr_in_order,
|
|
||||||
.num_coroutines = num_coroutines,
|
|
||||||
};
|
|
||||||
ret = convert_do_copy(&state);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
qemu_progress_print(100, 0);
|
qemu_progress_print(100, 0);
|
||||||
|
@ -2343,22 +2308,18 @@ out:
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
qemu_opts_free(create_opts);
|
qemu_opts_free(create_opts);
|
||||||
qemu_opts_del(sn_opts);
|
qemu_opts_del(sn_opts);
|
||||||
blk_unref(out_blk);
|
blk_unref(s.target);
|
||||||
g_free(bs);
|
if (s.src) {
|
||||||
if (blk) {
|
for (bs_i = 0; bs_i < s.src_num; bs_i++) {
|
||||||
for (bs_i = 0; bs_i < bs_n; bs_i++) {
|
blk_unref(s.src[bs_i]);
|
||||||
blk_unref(blk[bs_i]);
|
|
||||||
}
|
}
|
||||||
g_free(blk);
|
g_free(s.src);
|
||||||
}
|
}
|
||||||
g_free(bs_sectors);
|
g_free(s.src_sectors);
|
||||||
fail_getopt:
|
fail_getopt:
|
||||||
g_free(options);
|
g_free(options);
|
||||||
|
|
||||||
if (ret) {
|
return !!ret;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue