From 0cb8d47ba94c0e16f22e3e385dc7c60aea852eee Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:06 +0100 Subject: block: deprecate "encryption=on" in favor of "encrypt.format=aes" Historically the qcow & qcow2 image formats supported a property "encryption=on" to enable their built-in AES encryption. We'll soon be supporting LUKS for qcow2, so need a more general purpose way to enable encryption, with a choice of formats. This introduces an "encrypt.format" option, which will later be joined by a number of other "encrypt.XXX" options. The use of a "encrypt." prefix instead of "encrypt-" is done to facilitate mapping to a nested QAPI schema at later date. e.g. the preferred syntax is now qemu-img create -f qcow2 -o encrypt.format=aes demo.qcow2 Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-8-berrange@redhat.com Reviewed-by: Alberto Garcia Signed-off-by: Max Reitz --- qemu-img.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'qemu-img.c') diff --git a/qemu-img.c b/qemu-img.c index f7ffb79..ae4fe6d 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2264,6 +2264,8 @@ static int img_convert(int argc, char **argv) if (s.compressed) { bool encryption = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false); + const char *encryptfmt = + qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT); const char *preallocation = qemu_opt_get(opts, BLOCK_OPT_PREALLOC); @@ -2273,7 +2275,7 @@ static int img_convert(int argc, char **argv) goto out; } - if (encryption) { + if (encryption || encryptfmt) { error_report("Compression and encryption not supported at " "the same time"); ret = -1; -- cgit v1.1 From 788cf9f8c8cbda53843e060540f3e91a060eb744 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:15 +0100 Subject: block: rip out all traces of password prompting Now that qcow & qcow2 are wired up to get encryption keys via the QCryptoSecret object, nothing is relying on the interactive prompting for passwords. All the code related to password prompting can thus be ripped out. Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-17-berrange@redhat.com Signed-off-by: Max Reitz --- qemu-img.c | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'qemu-img.c') diff --git a/qemu-img.c b/qemu-img.c index ae4fe6d..7f1de74 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -260,29 +260,6 @@ static int print_block_option_help(const char *filename, const char *fmt) } -static int img_open_password(BlockBackend *blk, const char *filename, - int flags, bool quiet) -{ - BlockDriverState *bs; - char password[256]; - - bs = blk_bs(blk); - if (bdrv_is_encrypted(bs) && bdrv_key_required(bs) && - !(flags & BDRV_O_NO_IO)) { - qprintf(quiet, "Disk image '%s' is encrypted.\n", filename); - if (qemu_read_password(password, sizeof(password)) < 0) { - error_report("No password given"); - return -1; - } - if (bdrv_set_key(bs, password) < 0) { - error_report("invalid password"); - return -1; - } - } - return 0; -} - - static BlockBackend *img_open_opts(const char *optstr, QemuOpts *opts, int flags, bool writethrough, bool quiet, bool force_share) @@ -307,10 +284,6 @@ static BlockBackend *img_open_opts(const char *optstr, } blk_set_enable_write_cache(blk, !writethrough); - if (img_open_password(blk, optstr, flags, quiet) < 0) { - blk_unref(blk); - return NULL; - } return blk; } @@ -340,10 +313,6 @@ static BlockBackend *img_open_file(const char *filename, } blk_set_enable_write_cache(blk, !writethrough); - if (img_open_password(blk, filename, flags, quiet) < 0) { - blk_unref(blk); - return NULL; - } return blk; } -- cgit v1.1 From fd03c2b8fbf463f92413ed70a978bf70ebbc74c7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:36 +0100 Subject: qemu-img: add measure subcommand The measure subcommand calculates the size required by a new image file. This can be used by users or management tools that need to allocate space on an LVM volume, SAN LUN, etc before creating or converting an image file. Suggested-by: Maor Lipchuk Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-8-stefanha@redhat.com Signed-off-by: Max Reitz --- qemu-img.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) (limited to 'qemu-img.c') diff --git a/qemu-img.c b/qemu-img.c index 7f1de74..930ae88 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -61,6 +61,7 @@ enum { OPTION_FLUSH_INTERVAL = 261, OPTION_NO_DRAIN = 262, OPTION_TARGET_IMAGE_OPTS = 263, + OPTION_SIZE = 264, }; typedef enum OutputFormat { @@ -4419,6 +4420,239 @@ out: return 0; } +static void dump_json_block_measure_info(BlockMeasureInfo *info) +{ + QString *str; + QObject *obj; + Visitor *v = qobject_output_visitor_new(&obj); + + visit_type_BlockMeasureInfo(v, NULL, &info, &error_abort); + visit_complete(v, &obj); + str = qobject_to_json_pretty(obj); + assert(str != NULL); + printf("%s\n", qstring_get_str(str)); + qobject_decref(obj); + visit_free(v); + QDECREF(str); +} + +static int img_measure(int argc, char **argv) +{ + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {"object", required_argument, 0, OPTION_OBJECT}, + {"output", required_argument, 0, OPTION_OUTPUT}, + {"size", required_argument, 0, OPTION_SIZE}, + {"force-share", no_argument, 0, 'U'}, + {0, 0, 0, 0} + }; + OutputFormat output_format = OFORMAT_HUMAN; + BlockBackend *in_blk = NULL; + BlockDriver *drv; + const char *filename = NULL; + const char *fmt = NULL; + const char *out_fmt = "raw"; + char *options = NULL; + char *snapshot_name = NULL; + bool force_share = false; + QemuOpts *opts = NULL; + QemuOpts *object_opts = NULL; + QemuOpts *sn_opts = NULL; + QemuOptsList *create_opts = NULL; + bool image_opts = false; + uint64_t img_size = UINT64_MAX; + BlockMeasureInfo *info = NULL; + Error *local_err = NULL; + int ret = 1; + int c; + + while ((c = getopt_long(argc, argv, "hf:O:o:l:U", + long_options, NULL)) != -1) { + switch (c) { + case '?': + case 'h': + help(); + break; + case 'f': + fmt = optarg; + break; + case 'O': + out_fmt = optarg; + break; + case 'o': + if (!is_valid_option_list(optarg)) { + error_report("Invalid option list: %s", optarg); + goto out; + } + if (!options) { + options = g_strdup(optarg); + } else { + char *old_options = options; + options = g_strdup_printf("%s,%s", options, optarg); + g_free(old_options); + } + break; + case 'l': + if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { + sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts, + optarg, false); + if (!sn_opts) { + error_report("Failed in parsing snapshot param '%s'", + optarg); + goto out; + } + } else { + snapshot_name = optarg; + } + break; + case 'U': + force_share = true; + break; + case OPTION_OBJECT: + object_opts = qemu_opts_parse_noisily(&qemu_object_opts, + optarg, true); + if (!object_opts) { + goto out; + } + break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; + case OPTION_OUTPUT: + if (!strcmp(optarg, "json")) { + output_format = OFORMAT_JSON; + } else if (!strcmp(optarg, "human")) { + output_format = OFORMAT_HUMAN; + } else { + error_report("--output must be used with human or json " + "as argument."); + goto out; + } + break; + case OPTION_SIZE: + { + int64_t sval; + + sval = cvtnum(optarg); + if (sval < 0) { + if (sval == -ERANGE) { + error_report("Image size must be less than 8 EiB!"); + } else { + error_report("Invalid image size specified! You may use " + "k, M, G, T, P or E suffixes for "); + error_report("kilobytes, megabytes, gigabytes, terabytes, " + "petabytes and exabytes."); + } + goto out; + } + img_size = (uint64_t)sval; + } + break; + } + } + + if (qemu_opts_foreach(&qemu_object_opts, + user_creatable_add_opts_foreach, + NULL, NULL)) { + goto out; + } + + if (argc - optind > 1) { + error_report("At most one filename argument is allowed."); + goto out; + } else if (argc - optind == 1) { + filename = argv[optind]; + } + + if (!filename && + (object_opts || image_opts || fmt || snapshot_name || sn_opts)) { + error_report("--object, --image-opts, -f, and -l " + "require a filename argument."); + goto out; + } + if (filename && img_size != UINT64_MAX) { + error_report("--size N cannot be used together with a filename."); + goto out; + } + if (!filename && img_size == UINT64_MAX) { + error_report("Either --size N or one filename must be specified."); + goto out; + } + + if (filename) { + in_blk = img_open(image_opts, filename, fmt, 0, + false, false, force_share); + if (!in_blk) { + goto out; + } + + if (sn_opts) { + bdrv_snapshot_load_tmp(blk_bs(in_blk), + qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), + qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME), + &local_err); + } else if (snapshot_name != NULL) { + bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(in_blk), + snapshot_name, &local_err); + } + if (local_err) { + error_reportf_err(local_err, "Failed to load snapshot: "); + goto out; + } + } + + drv = bdrv_find_format(out_fmt); + if (!drv) { + error_report("Unknown file format '%s'", out_fmt); + goto out; + } + if (!drv->create_opts) { + error_report("Format driver '%s' does not support image creation", + drv->format_name); + goto out; + } + + create_opts = qemu_opts_append(create_opts, drv->create_opts); + create_opts = qemu_opts_append(create_opts, bdrv_file.create_opts); + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + if (options) { + qemu_opts_do_parse(opts, options, NULL, &local_err); + if (local_err) { + error_report_err(local_err); + error_report("Invalid options for file format '%s'", out_fmt); + goto out; + } + } + if (img_size != UINT64_MAX) { + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort); + } + + info = bdrv_measure(drv, opts, in_blk ? blk_bs(in_blk) : NULL, &local_err); + if (local_err) { + error_report_err(local_err); + goto out; + } + + if (output_format == OFORMAT_HUMAN) { + printf("required size: %" PRIu64 "\n", info->required); + printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated); + } else { + dump_json_block_measure_info(info); + } + + ret = 0; + +out: + qapi_free_BlockMeasureInfo(info); + qemu_opts_del(object_opts); + qemu_opts_del(opts); + qemu_opts_del(sn_opts); + qemu_opts_free(create_opts); + g_free(options); + blk_unref(in_blk); + return ret; +} static const img_cmd_t img_cmds[] = { #define DEF(option, callback, arg_string) \ -- cgit v1.1 From 3a691c50f10344b052ad70a4d0ed935276ccca3c Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:54 +0200 Subject: block: Add PreallocMode to blk_truncate() blk_truncate() itself will pass that value to bdrv_truncate(), and all callers of blk_truncate() just set the parameter to PREALLOC_MODE_OFF for now. Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-4-mreitz@redhat.com Signed-off-by: Max Reitz --- qemu-img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qemu-img.c') diff --git a/qemu-img.c b/qemu-img.c index 930ae88..1b74195 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3537,7 +3537,7 @@ static int img_resize(int argc, char **argv) goto out; } - ret = blk_truncate(blk, total_size, &err); + ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, &err); if (!ret) { qprintf(quiet, "Image resized.\n"); } else { -- cgit v1.1 From dc5f690b97ccdffa79fe7169bb26b0ebf06688bf Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:55 +0200 Subject: qemu-img: Expose PreallocMode for resizing Add a --preallocation command line option to qemu-img resize which can be used to set the PreallocMode parameter of blk_truncate(). While touching this code, fix the fact that we did not handle errors returned by blk_getlength(). Signed-off-by: Max Reitz Message-id: 20170613202107.10125-5-mreitz@redhat.com Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- qemu-img.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'qemu-img.c') diff --git a/qemu-img.c b/qemu-img.c index 1b74195..2802214 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu-version.h" #include "qapi/error.h" +#include "qapi/util.h" #include "qapi-visit.h" #include "qapi/qobject-output-visitor.h" #include "qapi/qmp/qerror.h" @@ -62,6 +63,7 @@ enum { OPTION_NO_DRAIN = 262, OPTION_TARGET_IMAGE_OPTS = 263, OPTION_SIZE = 264, + OPTION_PREALLOCATION = 265, }; typedef enum OutputFormat { @@ -3408,9 +3410,10 @@ static int img_resize(int argc, char **argv) Error *err = NULL; int c, ret, relative; const char *filename, *fmt, *size; - int64_t n, total_size; + int64_t n, total_size, current_size; bool quiet = false; BlockBackend *blk = NULL; + PreallocMode prealloc = PREALLOC_MODE_OFF; QemuOpts *param; static QemuOptsList resize_options = { @@ -3444,6 +3447,7 @@ static int img_resize(int argc, char **argv) {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, + {"preallocation", required_argument, 0, OPTION_PREALLOCATION}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, ":f:hq", @@ -3478,6 +3482,15 @@ static int img_resize(int argc, char **argv) case OPTION_IMAGE_OPTS: image_opts = true; break; + case OPTION_PREALLOCATION: + prealloc = qapi_enum_parse(PreallocMode_lookup, optarg, + PREALLOC_MODE__MAX, PREALLOC_MODE__MAX, + NULL); + if (prealloc == PREALLOC_MODE__MAX) { + error_report("Invalid preallocation mode '%s'", optarg); + return 1; + } + break; } } if (optind != argc - 1) { @@ -3526,8 +3539,16 @@ static int img_resize(int argc, char **argv) goto out; } + current_size = blk_getlength(blk); + if (current_size < 0) { + error_report("Failed to inquire current image length: %s", + strerror(-current_size)); + ret = -1; + goto out; + } + if (relative) { - total_size = blk_getlength(blk) + n * relative; + total_size = current_size + n * relative; } else { total_size = n; } @@ -3537,7 +3558,13 @@ static int img_resize(int argc, char **argv) goto out; } - ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, &err); + if (total_size <= current_size && prealloc != PREALLOC_MODE_OFF) { + error_report("Preallocation can only be used for growing images"); + ret = -1; + goto out; + } + + ret = blk_truncate(blk, total_size, prealloc, &err); if (!ret) { qprintf(quiet, "Image resized.\n"); } else { -- cgit v1.1