Signed-off-by: Dong Xu Wang <wdon...@linux.vnet.ibm.com> Signed-off-by: Chunyan Liu <cy...@suse.com> --- block/qcow2.c | 325 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 167 insertions(+), 158 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c index dcd43bc..e0f00bf 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1455,7 +1455,7 @@ static int preallocate(BlockDriverState *bs) static int qcow2_create2(const char *filename, int64_t total_size, const char *backing_file, const char *backing_format, int flags, size_t cluster_size, int prealloc, - QEMUOptionParameter *options, int version, + QemuOpts *opts, int version, Error **errp) { /* Calculate cluster_bits */ @@ -1487,7 +1487,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, Error *local_err = NULL; int ret; - ret = bdrv_create_file(filename, options, NULL, &local_err); + ret = bdrv_create_file(filename, NULL, opts, &local_err); if (ret < 0) { error_propagate(errp, local_err); return ret; @@ -1622,11 +1622,11 @@ out: return ret; } -static int qcow2_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) { - const char *backing_file = NULL; - const char *backing_fmt = NULL; + char *backing_file = NULL; + char *backing_fmt = NULL; + char *buf; uint64_t sectors = 0; int flags = 0; size_t cluster_size = DEFAULT_CLUSTER_SIZE; @@ -1636,64 +1636,64 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options, int ret; /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - sectors = options->value.n / 512; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { - backing_file = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) { - backing_fmt = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) { - flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0; - } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) { - if (options->value.n) { - cluster_size = options->value.n; - } - } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) { - if (!options->value.s || !strcmp(options->value.s, "off")) { - prealloc = 0; - } else if (!strcmp(options->value.s, "metadata")) { - prealloc = 1; - } else { - error_setg(errp, "Invalid preallocation mode: '%s'", - options->value.s); - return -EINVAL; - } - } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) { - if (!options->value.s) { - /* keep the default */ - } else if (!strcmp(options->value.s, "0.10")) { - version = 2; - } else if (!strcmp(options->value.s, "1.1")) { - version = 3; - } else { - error_setg(errp, "Invalid compatibility level: '%s'", - options->value.s); - return -EINVAL; - } - } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) { - flags |= options->value.n ? BLOCK_FLAG_LAZY_REFCOUNTS : 0; - } - options++; + sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512; + backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); + backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { + flags |= BLOCK_FLAG_ENCRYPT; + } + cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, + DEFAULT_CLUSTER_SIZE); + buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); + if (!buf || !strcmp(buf, "off")) { + prealloc = 0; + } else if (!strcmp(buf, "metadata")) { + prealloc = 1; + } else { + fprintf(stderr, "Invalid preallocation mode: '%s'\n", buf); + ret = -EINVAL; + goto finish; + } + g_free(buf); + buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL); + if (!buf || !strcmp(buf, "0.10")) { + version = 2; + } else if (!strcmp(buf, "1.1")) { + version = 3; + } else { + fprintf(stderr, "Invalid compatibility level: '%s'\n", buf); + ret = -EINVAL; + goto finish; + } + + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_LAZY_REFCOUNTS, false)) { + flags |= BLOCK_FLAG_LAZY_REFCOUNTS; } if (backing_file && prealloc) { error_setg(errp, "Backing file and preallocation cannot be used at " "the same time"); - return -EINVAL; + ret = -EINVAL; + goto finish; } if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) { error_setg(errp, "Lazy refcounts only supported with compatibility " "level 1.1 and above (use compat=1.1 or greater)"); - return -EINVAL; + ret = -EINVAL; + goto finish; } ret = qcow2_create2(filename, sectors, backing_file, backing_fmt, flags, - cluster_size, prealloc, options, version, &local_err); + cluster_size, prealloc, opts, version, &local_err); if (local_err) { error_propagate(errp, local_err); } + +finish: + g_free(backing_file); + g_free(backing_fmt); + g_free(buf); return ret; } @@ -2058,66 +2058,61 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version) return 0; } -static int qcow2_amend_options(BlockDriverState *bs, - QEMUOptionParameter *options) +static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts) { BDRVQcowState *s = bs->opaque; int old_version = s->qcow_version, new_version = old_version; uint64_t new_size = 0; - const char *backing_file = NULL, *backing_format = NULL; + char *backing_file = NULL, *backing_format = NULL; bool lazy_refcounts = s->use_lazy_refcounts; + char *compat = NULL, *prealloc = NULL; + uint64_t cluster_size = s->cluster_size; + bool encrypt; int ret; - int i; - for (i = 0; options[i].name; i++) - { - if (!options[i].assigned) { - /* only change explicitly defined options */ - continue; - } + compat = qemu_opt_get_del(opts, "compat"); + if (!compat) { + /* preserve default */ + } else if (!strcmp(compat, "0.10")) { + new_version = 2; + } else if (!strcmp(compat, "1.1")) { + new_version = 3; + } else { + fprintf(stderr, "Unknown compatibility level %s.\n", compat); + ret = -EINVAL; + goto finish; + } - if (!strcmp(options[i].name, "compat")) { - if (!options[i].value.s) { - /* preserve default */ - } else if (!strcmp(options[i].value.s, "0.10")) { - new_version = 2; - } else if (!strcmp(options[i].value.s, "1.1")) { - new_version = 3; - } else { - fprintf(stderr, "Unknown compatibility level %s.\n", - options[i].value.s); - return -EINVAL; - } - } else if (!strcmp(options[i].name, "preallocation")) { - fprintf(stderr, "Cannot change preallocation mode.\n"); - return -ENOTSUP; - } else if (!strcmp(options[i].name, "size")) { - new_size = options[i].value.n; - } else if (!strcmp(options[i].name, "backing_file")) { - backing_file = options[i].value.s; - } else if (!strcmp(options[i].name, "backing_fmt")) { - backing_format = options[i].value.s; - } else if (!strcmp(options[i].name, "encryption")) { - if ((options[i].value.n != !!s->crypt_method)) { - fprintf(stderr, "Changing the encryption flag is not " - "supported.\n"); - return -ENOTSUP; - } - } else if (!strcmp(options[i].name, "cluster_size")) { - if (options[i].value.n != s->cluster_size) { - fprintf(stderr, "Changing the cluster size is not " - "supported.\n"); - return -ENOTSUP; - } - } else if (!strcmp(options[i].name, "lazy_refcounts")) { - lazy_refcounts = options[i].value.n; - } else { - /* if this assertion fails, this probably means a new option was - * added without having it covered here */ - assert(false); - } + prealloc = qemu_opt_get_del(opts, "preallocation"); + if (prealloc) { + fprintf(stderr, "Cannot change preallocation mode.\n"); + ret = -ENOTSUP; + goto finish; + } + + new_size = qemu_opt_get_size_del(opts, "size", 0); + backing_file = qemu_opt_get_del(opts, "backing_file"); + backing_format = qemu_opt_get_del(opts, "backing_fmt"); + + encrypt = qemu_opt_get_bool_del(opts, "encryption", s->crypt_method); + if (encrypt != !!s->crypt_method) { + fprintf(stderr, "Changing the encryption flag is not " + "supported.\n"); + ret = -ENOTSUP; + goto finish; } + cluster_size = qemu_opt_get_size_del(opts, "cluster_size", cluster_size); + if (cluster_size != s->cluster_size) { + fprintf(stderr, "Changing the cluster size is not " + "supported.\n"); + ret = -ENOTSUP; + goto finish; + } + + lazy_refcounts = qemu_opt_get_bool_del(opts, "lazy_refcounts", + lazy_refcounts); + if (new_version != old_version) { if (new_version > old_version) { /* Upgrade */ @@ -2125,12 +2120,12 @@ static int qcow2_amend_options(BlockDriverState *bs, ret = qcow2_update_header(bs); if (ret < 0) { s->qcow_version = old_version; - return ret; + goto finish; } } else { ret = qcow2_downgrade(bs, new_version); if (ret < 0) { - return ret; + goto finish; } } } @@ -2139,7 +2134,7 @@ static int qcow2_amend_options(BlockDriverState *bs, ret = qcow2_change_backing_file(bs, backing_file ?: bs->backing_file, backing_format ?: bs->backing_format); if (ret < 0) { - return ret; + goto finish; } } @@ -2148,27 +2143,28 @@ static int qcow2_amend_options(BlockDriverState *bs, if (s->qcow_version < 3) { fprintf(stderr, "Lazy refcounts only supported with compatibility " "level 1.1 and above (use compat=1.1 or greater)\n"); - return -EINVAL; + ret = -EINVAL; + goto finish; } s->compatible_features |= QCOW2_COMPAT_LAZY_REFCOUNTS; ret = qcow2_update_header(bs); if (ret < 0) { s->compatible_features &= ~QCOW2_COMPAT_LAZY_REFCOUNTS; - return ret; + goto finish; } s->use_lazy_refcounts = true; } else { /* make image clean first */ ret = qcow2_mark_clean(bs); if (ret < 0) { - return ret; + goto finish; } /* now disallow lazy refcounts */ s->compatible_features &= ~QCOW2_COMPAT_LAZY_REFCOUNTS; ret = qcow2_update_header(bs); if (ret < 0) { s->compatible_features |= QCOW2_COMPAT_LAZY_REFCOUNTS; - return ret; + goto finish; } s->use_lazy_refcounts = false; } @@ -2177,56 +2173,69 @@ static int qcow2_amend_options(BlockDriverState *bs, if (new_size) { ret = bdrv_truncate(bs, new_size); if (ret < 0) { - return ret; + goto finish; } } - return 0; + ret = 0; + +finish: + g_free(backing_file); + g_free(backing_format); + g_free(compat); + g_free(prealloc); + return ret; } -static QEMUOptionParameter qcow2_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_COMPAT_LEVEL, - .type = OPT_STRING, - .help = "Compatibility level (0.10 or 1.1)" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = OPT_STRING, - .help = "File name of a base image" - }, - { - .name = BLOCK_OPT_BACKING_FMT, - .type = OPT_STRING, - .help = "Image format of the base image" - }, - { - .name = BLOCK_OPT_ENCRYPT, - .type = OPT_FLAG, - .help = "Encrypt the image" - }, - { - .name = BLOCK_OPT_CLUSTER_SIZE, - .type = OPT_SIZE, - .help = "qcow2 cluster size", - .value = { .n = DEFAULT_CLUSTER_SIZE }, - }, - { - .name = BLOCK_OPT_PREALLOC, - .type = OPT_STRING, - .help = "Preallocation mode (allowed values: off, metadata)" - }, - { - .name = BLOCK_OPT_LAZY_REFCOUNTS, - .type = OPT_FLAG, - .help = "Postpone refcount updates", - }, - { NULL } +static QemuOptsList qcow2_create_opts = { + .name = "qcow2-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_COMPAT_LEVEL, + .type = QEMU_OPT_STRING, + .help = "Compatibility level (0.10 or 1.1)" + }, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of a base image" + }, + { + .name = BLOCK_OPT_BACKING_FMT, + .type = QEMU_OPT_STRING, + .help = "Image format of the base image" + }, + { + .name = BLOCK_OPT_ENCRYPT, + .type = QEMU_OPT_BOOL, + .help = "Encrypt the image", + .def_value_str = "off" + }, + { + .name = BLOCK_OPT_CLUSTER_SIZE, + .type = QEMU_OPT_SIZE, + .help = "qcow2 cluster size", + .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) + }, + { + .name = BLOCK_OPT_PREALLOC, + .type = QEMU_OPT_STRING, + .help = "Preallocation mode (allowed values: off, metadata)" + }, + { + .name = BLOCK_OPT_LAZY_REFCOUNTS, + .type = QEMU_OPT_BOOL, + .help = "Postpone refcount updates", + .def_value_str = "off" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_qcow2 = { @@ -2236,10 +2245,10 @@ static BlockDriver bdrv_qcow2 = { .bdrv_open = qcow2_open, .bdrv_close = qcow2_close, .bdrv_reopen_prepare = qcow2_reopen_prepare, - .bdrv_create = qcow2_create, - .bdrv_has_zero_init = bdrv_has_zero_init_1, + .bdrv_create2 = qcow2_create, + .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_get_block_status = qcow2_co_get_block_status, - .bdrv_set_key = qcow2_set_key, + .bdrv_set_key = qcow2_set_key, .bdrv_co_readv = qcow2_co_readv, .bdrv_co_writev = qcow2_co_writev, @@ -2254,8 +2263,8 @@ static BlockDriver bdrv_qcow2 = { .bdrv_snapshot_goto = qcow2_snapshot_goto, .bdrv_snapshot_delete = qcow2_snapshot_delete, .bdrv_snapshot_list = qcow2_snapshot_list, - .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, - .bdrv_get_info = qcow2_get_info, + .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, + .bdrv_get_info = qcow2_get_info, .bdrv_get_specific_info = qcow2_get_specific_info, .bdrv_save_vmstate = qcow2_save_vmstate, @@ -2266,9 +2275,9 @@ static BlockDriver bdrv_qcow2 = { .bdrv_refresh_limits = qcow2_refresh_limits, .bdrv_invalidate_cache = qcow2_invalidate_cache, - .create_options = qcow2_create_options, - .bdrv_check = qcow2_check, - .bdrv_amend_options = qcow2_amend_options, + .create_opts = &qcow2_create_opts, + .bdrv_check = qcow2_check, + .bdrv_amend_options2 = qcow2_amend_options, }; static void bdrv_qcow2_init(void) -- 1.7.12.4